@fased/fased 0.1.67 → 0.1.69
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 +27 -0
- package/README.md +20 -22
- package/config/sat-runtime.env +6 -2
- package/config/signer-protocol-v2.json +10 -0
- package/dist/agents/tools/wallet-action-tool.js +2 -0
- package/dist/agents/tools/wallet-tool.js +5 -3
- package/dist/brand.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/cli/program/register.wallet.js +119 -5
- package/dist/commands/wallet.js +1286 -74
- package/dist/config/sat-runtime-ids.js +6 -1
- package/dist/control-ui/assets/{app-De8gTtZU.js → app-BLFLoFPk.js} +1526 -1526
- package/dist/control-ui/assets/{federation-DgA9e-Pn.js → federation-SGMAnM_8.js} +2 -2
- package/dist/control-ui/assets/{index-DYYBRBOS.js → index-S88kp5ZQ.js} +3 -3
- package/dist/control-ui/assets/{mining-Dg-3ll0F.js → mining-ClI8RW4u.js} +2 -2
- package/dist/control-ui/assets/{wallet-DvStR_AT.js → wallet-CRIhDQbW.js} +325 -156
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/gateway/server-http.js +394 -55
- package/dist/mining/mainnet-sync.js +67 -5
- package/dist/operator/operator-readiness.js +1 -1
- package/dist/plugin-sdk/{actions-DRu135h0.js → actions-B-Vwj64K.js} +3 -3
- package/dist/plugin-sdk/{allow-list-DyAxs4yw.js → allow-list-Bf45HfoP.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-Dq_rJtqH.js → audio-preflight-CS7Q_7-R.js} +26 -25
- package/dist/plugin-sdk/{audit-C5d2z5U1.js → audit-CUULWG22.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-DaI5wevh.js → channel-access-configure-BoUsC-Ys.js} +1 -1
- package/dist/plugin-sdk/{channel-adapters.discord-BS4S4Svh.js → channel-adapters.discord-DSiR4X2Y.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
- package/dist/plugin-sdk/channel-plugin-common.js +1 -1
- package/dist/plugin-sdk/{chunk-CyoyqpbG.js → chunk-CBpl-AiQ.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-Dunoq4Er.js → chunk-items-BLBZNORg.js} +1 -1
- package/dist/plugin-sdk/command-status.js +26 -25
- package/dist/plugin-sdk/{commands-registry-BfqdEWdF.js → commands-registry-G5KXSi_y.js} +1 -1
- package/dist/plugin-sdk/{config-schema--vl89M7d.js → config-schema-BiBOUW89.js} +431 -125
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/{diagnostic-DLL_zekv.js → diagnostic-sYs6Agr-.js} +1 -1
- package/dist/plugin-sdk/{directory-live-CSuYxdwk.js → directory-live-BXMpuYAF.js} +1 -1
- package/dist/plugin-sdk/{directory-live-Dw7ZgC9_.js → directory-live-Rn1BzPof.js} +1 -1
- package/dist/plugin-sdk/discord.d.ts +4 -4
- package/dist/plugin-sdk/discord.js +20 -20
- package/dist/plugin-sdk/{draft-stream-controls-BqchW1vi.js → draft-stream-controls-CMNdKSx-.js} +1 -1
- package/dist/plugin-sdk/{guilds-CDhRIX57.js → guilds-Dkwl0yHv.js} +1 -1
- package/dist/plugin-sdk/{handle-action-hvwapMKg.js → handle-action-CRdM6B-8.js} +15 -15
- package/dist/plugin-sdk/index.d.ts +15 -15
- package/dist/plugin-sdk/index.js +28 -27
- package/dist/plugin-sdk/{login-Ca583Okc.js → login-D7WnK8-P.js} +1 -1
- package/dist/plugin-sdk/{login-qr-CGciBSNP.js → login-qr-CRueOKZK.js} +2 -114
- package/dist/plugin-sdk/{markdown-tables-DCOXEUfZ.js → markdown-tables-d7GlUs5R.js} +1 -1
- package/dist/plugin-sdk/{media-CAdQF5TG.js → media-BAoaxCrt.js} +1 -1
- package/dist/plugin-sdk/{monitor-DrTy_4CL.js → monitor-WXdn4mR-.js} +34 -33
- package/dist/plugin-sdk/{monitor-CV1sr0p2.js → monitor-xzVAPbg2.js} +44 -43
- package/dist/plugin-sdk/{openresponses-http-BAjgURZa.js → openresponses-http-DnI1LFgq.js} +26 -25
- package/dist/plugin-sdk/{outbound-attachment-QqTnIhZL.js → outbound-attachment-CyXM3cAv.js} +1 -1
- package/dist/plugin-sdk/{outbound-BgVDdHxx.js → outbound-zB6llMGW.js} +6 -6
- package/dist/plugin-sdk/{pairing-message-BjIJYVvp.d.ts → pairing-message-CiTcdD6m.d.ts} +1 -1
- package/dist/plugin-sdk/{pairing-store-BChahgI2.js → pairing-store-B6J2C0vP.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DxTMz_XF.js → pi-model-discovery-runtime-6JzLw9Gk.js} +1 -1
- package/dist/plugin-sdk/{probe-CJb5uR8B.js → probe-BM7Oe40M.js} +2 -2
- package/dist/plugin-sdk/{probe-l_whvGLY.js → probe-CMPksimh.js} +1 -1
- package/dist/plugin-sdk/{probe-BFroeK3g.js → probe-oVp12D6L.js} +1 -1
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
- package/dist/plugin-sdk/{pw-ai-DlxqX6Es.js → pw-ai-DZYLDC-S.js} +1 -1
- package/dist/plugin-sdk/qr-image-B4MlMG4N.js +115 -0
- package/dist/plugin-sdk/{replies-ChYo5ZQM.js → replies-CY-V0Zob.js} +3 -3
- package/dist/plugin-sdk/{resolve-channels-87LZrFk_.js → resolve-channels-1HtDcMqh.js} +2 -2
- package/dist/plugin-sdk/{resolve-channels-_-nV-EK2.js → resolve-channels-CU72Qh2j.js} +1 -1
- package/dist/plugin-sdk/{resolve-outbound-target-D-KGgHJZ.js → resolve-outbound-target-nQSBVYz9.js} +2 -2
- package/dist/plugin-sdk/{resolve-route-C8tvQm8Z.js → resolve-route-Dufnu2cT.js} +1 -1
- package/dist/plugin-sdk/{resolve-users-DN9VQBwv.js → resolve-users-Bk_ss2vC.js} +1 -1
- package/dist/plugin-sdk/{resolve-users-V6dHh_2B.js → resolve-users-IevCOk4W.js} +2 -2
- package/dist/plugin-sdk/{runtime-2B9_WKoI.js → runtime-CXSQwMaR.js} +1 -1
- package/dist/plugin-sdk/{runtime-dependency-nup8niQL.js → runtime-dependency-DczkvPxn.js} +9 -9
- package/dist/plugin-sdk/sat-runtime.d.ts +105 -10
- package/dist/plugin-sdk/sat-runtime.js +26 -25
- package/dist/plugin-sdk/{send-DCO441U7.js → send-BXBS_mRK.js} +8 -8
- package/dist/plugin-sdk/{send-CFzGKJXo.js → send-D-HfKQZm.js} +4 -4
- package/dist/plugin-sdk/{send-B6KkGKZD.js → send-D1j12ZgX.js} +5 -5
- package/dist/plugin-sdk/{send-q9HXrSwK.js → send-DWKm6yay.js} +10 -10
- package/dist/plugin-sdk/{send-gDoGA-7e.js → send-Di1Jit3L.js} +7 -7
- package/dist/plugin-sdk/{skill-commands-FKEPLS7T.js → skill-commands-iJtvpqgb.js} +2 -2
- package/dist/plugin-sdk/{slack-DSC6T2KW.js → slack-CkIRVDUK.js} +45 -44
- package/dist/plugin-sdk/{slack-actions-DhbMcp8M.js → slack-actions-BzUEszJa.js} +10 -10
- package/dist/plugin-sdk/slack.d.ts +4 -4
- package/dist/plugin-sdk/slack.js +6 -6
- package/dist/plugin-sdk/{sticker-cache-C0l_5IKg.js → sticker-cache-Dpap5ce_.js} +2 -2
- package/dist/plugin-sdk/{tables-B3jr0Pvq.js → tables-_1W36GII.js} +2 -2
- package/dist/plugin-sdk/{targets-CtSbTxYX.js → targets-DDbNnLnB.js} +2 -2
- package/dist/plugin-sdk/{telegram-actions-BwGBIVDE.js → telegram-actions-Cewdga8H.js} +30 -29
- package/dist/plugin-sdk/telegram.d.ts +4 -4
- package/dist/plugin-sdk/telegram.js +3 -3
- package/dist/plugin-sdk/{thread-bindings.lifecycle-QbkNl-m6.js → thread-bindings.lifecycle-Y9T3CQGf.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-D9hg_M1c.js → thread-bindings.state-D2oOWDpv.js} +1 -1
- package/dist/plugin-sdk/{tmp-fased-dir-DXnGKKgi.d.ts → tmp-fased-dir-BSEHc8MQ.d.ts} +8 -2
- package/dist/plugin-sdk/{types-eG9aYqXF.d.ts → types-BakzIzGN.d.ts} +1 -1
- package/dist/plugin-sdk/{types-Cegc86EP.d.ts → types-CzF0YQqK.d.ts} +3 -3
- package/dist/plugin-sdk/{web-C_AH5PyB.js → web-DGWi7i3B.js} +33 -32
- package/dist/plugin-sdk/{whatsapp-actions-Bj_rOncr.js → whatsapp-actions-Blu9-eX-.js} +9 -9
- package/dist/plugin-sdk/{whatsapp-heartbeat-B1WHkJIg.js → whatsapp-heartbeat-DjmQM7hq.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +9 -9
- package/dist/plugin-sdk/whatsapp.js +7 -7
- package/dist/plugin-sdk/{wsl-J-HscWxS.js → wsl-CTvIWvZz.js} +1 -1
- package/dist/plugin-sdk/{zod-schema.providers-core-FaYR6KdD.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
- package/dist/wallet/local-socket-signer-lifecycle.js +107 -3
- package/dist/wallet/local-socket-signer-protocol.js +97 -10
- package/dist/wallet/mining-wallet-retirement.js +256 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +10 -0
- package/dist/wallet/signer-network-admin.js +11 -118
- package/dist/wallet/signer-protocol-v2.generated.js +10 -0
- package/dist/wallet/solana-assets.js +9 -3
- package/dist/wallet/solana-rpc-read-fetch.js +65 -0
- package/dist/wallet/wallet-agent-selection.js +6 -10
- package/dist/wallet/wallet-provider-registry.js +70 -29
- package/dist/wallet/wallet-send-approvals.js +6 -2
- package/dist/wallet/wallet-status.js +63 -1
- package/dist/web/login-qr.js +1 -1
- package/dist/wizard/onboarding.js +86 -84
- package/dist/wizard/onboarding.wallet.js +10 -1
- 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/package.json +1 -1
- 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 +286 -107
- package/package.json +4 -2
- package/scripts/fased-managed-updater.mjs +10 -2
- package/scripts/install-fased-signerd.sh +4 -8
- package/scripts/install-managed-runtime.mjs +10 -7
- package/scripts/install-runtime-profile.sh +27 -0
- package/scripts/start-managed.sh +13 -1
- /package/dist/plugin-sdk/{active-listener-B_NMtgPL.js → active-listener-p9Ooc1qj.js} +0 -0
- /package/dist/plugin-sdk/{blocks-input-Bg-8S2pl.js → blocks-input-DiZaqaN7.js} +0 -0
- /package/dist/plugin-sdk/{channel-access-CcFRdRPO.js → channel-access-B0aZBSd2.js} +0 -0
- /package/dist/plugin-sdk/{channel-activity-DBDMQ3yI.js → channel-activity-F07DjroV.js} +0 -0
- /package/dist/plugin-sdk/{channel-core-CFRs8LPy.js → channel-core-DoF4X04L.js} +0 -0
- /package/dist/plugin-sdk/{client-pI228AVT.js → client-DLY-kWF_.js} +0 -0
- /package/dist/plugin-sdk/{command-poll-backoff-yJU83wEq.js → command-poll-backoff-NAePk3eL.js} +0 -0
- /package/dist/plugin-sdk/{date-time-uUevHscU.js → date-time-ChY_tHoG.js} +0 -0
- /package/dist/plugin-sdk/{draft-stream-loop-CrOPfV3F.js → draft-stream-loop-DMBwjjd1.js} +0 -0
- /package/dist/plugin-sdk/{fetch-BtmoPIlf.js → fetch-B0v6OTUZ.js} +0 -0
- /package/dist/plugin-sdk/{filesystem-manager-DoI8IBNF.js → filesystem-manager-BzuIJ9K9.js} +0 -0
- /package/dist/plugin-sdk/{gateway-registry-DZDsqicG.js → gateway-registry-Bgl2GFgy.js} +0 -0
- /package/dist/plugin-sdk/{inbound-context-DrAcXE0y.js → inbound-context-CQnfFFQ9.js} +0 -0
- /package/dist/plugin-sdk/{pi-model-discovery-BX_JLcEJ.js → pi-model-discovery-BHNVyRny.js} +0 -0
- /package/dist/plugin-sdk/{polls-DKQXVfJp.js → polls-DXd67TD8.js} +0 -0
- /package/dist/plugin-sdk/{proxy-DWpYcsvR.js → proxy-CLRUdShp.js} +0 -0
- /package/dist/plugin-sdk/{qmd-manager-CgRaTxUq.js → qmd-manager-B8Vnu0ND.js} +0 -0
- /package/dist/plugin-sdk/{render-e7fENCYH.js → render-DrBfVs0u.js} +0 -0
- /package/dist/plugin-sdk/{reply-reference-Bqk-7HXE.js → reply-reference-BnAk5Wjb.js} +0 -0
- /package/dist/plugin-sdk/{retry-policy-C6SjKjQA.js → retry-policy-CXh1owkc.js} +0 -0
- /package/dist/plugin-sdk/{sandbox-paths-Dx2lUqCu.js → sandbox-paths-Bzh1CuZc.js} +0 -0
- /package/dist/plugin-sdk/{session-DHD4ZKyG.js → session-iuGR_rdi.js} +0 -0
- /package/dist/plugin-sdk/{shared-CBgp_GBw.js → shared-D1AD2Ejn.js} +0 -0
- /package/dist/plugin-sdk/{target-errors-Ckufe179.js → target-errors-DfS1sLR9.js} +0 -0
- /package/dist/plugin-sdk/{tool-loop-detection-Bp8bPJLs.js → tool-loop-detection-sDZl27w7.js} +0 -0
- /package/dist/plugin-sdk/{ui-Be8cLHIS.js → ui-GQDYm_jw.js} +0 -0
- /package/dist/plugin-sdk/{with-timeout-ckWB8rTo.js → with-timeout-CVV8tytk.js} +0 -0
|
@@ -11,6 +11,7 @@ import { resolveLocalSignerSocketPath, resolveWalletRuntimeConfig } from "../wal
|
|
|
11
11
|
import { WALLET_PROVIDER_IDS, checkNamedWalletDeletionSafety, deleteNamedWallet, normalizeWalletUserRole, readWalletProviderRegistry, resolveWalletSelection, resolveWalletUserRole, setAgentWalletAssignment, setDefaultWallet, setNamedWalletRole, setWalletProviderEnabled, upsertNamedWallet } from "../wallet/wallet-provider-registry.js";
|
|
12
12
|
import { resolveAgentPublicOrigin, resolveFederationBaseUrl, resolveFederationBondWalletId, resolveFederationHandle } from "../federation/runtime.js";
|
|
13
13
|
import { isValidSolanaAddress } from "../wallet/solana-address.js";
|
|
14
|
+
import { fetchPinnedSolanaRpcRead } from "../wallet/solana-rpc-read-fetch.js";
|
|
14
15
|
import { fetchSolanaMintInfoViaRpc, fetchSolanaNativeBalanceViaRpc, fetchSolanaTokenBalanceViaRpc, fetchSolanaWalletAssetsViaRpc, invalidateSolanaAssetRpcCaches, summarizeSolanaAssetRpcMetrics } from "../wallet/solana-assets.js";
|
|
15
16
|
import { tryResolveSatRuntimeIds } from "../config/sat-runtime-ids.js";
|
|
16
17
|
import { commitWalletPolicyConfigUpdate, prepareWalletPolicyConfigUpdate, resolveWalletPolicyConfig, resolveWalletRecurringTransferPolicy } from "../wallet/wallet-policy.js";
|
|
@@ -28,19 +29,22 @@ import { normalizeCanvasScopedUrl } from "./canvas-capability.js";
|
|
|
28
29
|
import { A2UI_PATH, CANVAS_HOST_PATH, CANVAS_WS_PATH, handleA2uiHttpRequest } from "../canvas-host/a2ui.js";
|
|
29
30
|
import { resolveFederationBondWallet } from "../wallet/solana-bond-signing.js";
|
|
30
31
|
import { createAndSubmitFederationBondProof, loadPersistedFederationBondProof, submitFederationBondProof } from "../federation/auto-connect.js";
|
|
32
|
+
import { resolveNativeSignerWalletId } from "../wallet/native-signer-wallet-id.js";
|
|
31
33
|
import { beginWalletApprovalAssertion, beginWalletPasskeyRegistration, consumeWalletApprovalGrant, createWalletApprovalChallenge, finishWalletApprovalAssertion, finishWalletPasskeyRegistration, listWalletPasskeys, readWalletApprovalAuthSnapshot, removeWalletPasskey, resolveWalletApprovalAuthMode, resolveWalletApprovalChallengeTtlSeconds, resolveWalletApprovalGrantTtlSeconds } from "../wallet/wallet-approval-auth.js";
|
|
32
34
|
import { readWalletStatusSnapshot } from "../wallet/wallet-status.js";
|
|
33
35
|
import { inspectSatBondPosition, inspectSatBondStakingDistributor, inspectSatBondStakingPosition, inspectSatChainSlot, invalidateSatReadCaches } from "../extensions/sat-mining/src/rpc-read.js";
|
|
34
36
|
import { digestSatSubmissionIntent } from "../extensions/sat-mining/src/submission-ledger.js";
|
|
35
37
|
import { runWithSatSubmissionWorkflow, submitSatCancelBondUnlock, submitSatClaimBondStakingRewards, submitSatFinalizeBondUnlock, submitSatIncreaseBondPosition, submitSatOpenBondPosition, submitSatRequestBondUnlock, submitSatSyncBondStakingPosition, submitSatSyncBondStakingRewards } from "../extensions/sat-mining/src/solana-submit.js";
|
|
36
38
|
import { resolveAgentAvatar } from "../agents/identity-avatar.js";
|
|
37
|
-
import {
|
|
39
|
+
import { configureSignerOwnedWalletNetwork } from "../wallet/signer-network-admin.js";
|
|
38
40
|
import { listWalletInboundEvents, pollWalletInboundEvents, reconcileWalletInboundEvents, recordWalletInboundWebhookEvent } from "../wallet/wallet-inbound-events.js";
|
|
39
41
|
import { walletSetupCommand } from "../commands/wallet.js";
|
|
40
42
|
import { getDiagnosticStabilitySnapshot } from "../logging/diagnostic-stability.js";
|
|
41
43
|
import { resolveManagedFederationPublicUrl } from "../managed/federation.js";
|
|
44
|
+
import { lockSignerOwnedWalletForArchive } from "../wallet/local-socket-signer-archive.js";
|
|
42
45
|
import { LocalSignerPolicyAdminRequiredError, buildLocalSignerPolicyTightening, localSignerPolicyState } from "../wallet/local-socket-signer-policy.js";
|
|
43
46
|
import { executeWalletStandardReview, prepareWalletStandardReview, readWalletStandardReviewTxHash } from "../wallet/wallet-standard-review.js";
|
|
47
|
+
import { renderQrPngBase64 } from "../web/qr-image.js";
|
|
44
48
|
import { createA2aHandler } from "./a2a-http.js";
|
|
45
49
|
import { CONTROL_UI_BOOT_CHECK_PATH, resolveControlUiBootCheck } from "./control-ui-boot-check.js";
|
|
46
50
|
import { normalizePublicHost, resolveControlUiPublicHost } from "./control-ui-login.js";
|
|
@@ -100,12 +104,19 @@ function parseCookies(raw) {
|
|
|
100
104
|
}
|
|
101
105
|
return cookies;
|
|
102
106
|
}
|
|
103
|
-
function
|
|
107
|
+
function normalizeHostName(host) {
|
|
104
108
|
const raw = host.trim().toLowerCase();
|
|
105
|
-
|
|
109
|
+
return raw.startsWith("[") ? (() => {
|
|
106
110
|
const end = raw.indexOf("]");
|
|
107
111
|
return end > 0 ? raw.slice(1, end) : raw;
|
|
108
112
|
})() : raw.replace(/:\d+$/, "");
|
|
113
|
+
}
|
|
114
|
+
function isLiteralLoopbackHostName(host) {
|
|
115
|
+
const normalized = normalizeHostName(host);
|
|
116
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
|
|
117
|
+
}
|
|
118
|
+
function isLocalHostName(host) {
|
|
119
|
+
const normalized = normalizeHostName(host);
|
|
109
120
|
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized.endsWith(".local");
|
|
110
121
|
}
|
|
111
122
|
function isLoopbackBrowserOrigin(origin) {
|
|
@@ -114,7 +125,18 @@ function isLoopbackBrowserOrigin(origin) {
|
|
|
114
125
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
115
126
|
return false;
|
|
116
127
|
}
|
|
117
|
-
return
|
|
128
|
+
return isLiteralLoopbackHostName(parsed.host);
|
|
129
|
+
} catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function isSameBrowserOriginHost(origin, host) {
|
|
134
|
+
try {
|
|
135
|
+
const parsed = new URL(origin);
|
|
136
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return parsed.host.toLowerCase() === host.trim().toLowerCase();
|
|
118
140
|
} catch {
|
|
119
141
|
return false;
|
|
120
142
|
}
|
|
@@ -132,7 +154,7 @@ function applyLoopbackCorsIfAllowed(req, res, host) {
|
|
|
132
154
|
if (!origin) {
|
|
133
155
|
return false;
|
|
134
156
|
}
|
|
135
|
-
if (!isLocalHostName(host) || !isLoopbackBrowserOrigin(origin)) {
|
|
157
|
+
if (!isLocalHostName(host) || !isLoopbackBrowserOrigin(origin) && !isSameBrowserOriginHost(origin, host)) {
|
|
136
158
|
return false;
|
|
137
159
|
}
|
|
138
160
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
@@ -659,7 +681,7 @@ async function readWalletSettingsSignerPolicy(params) {
|
|
|
659
681
|
...asset,
|
|
660
682
|
destinations: [...asset.destinations]
|
|
661
683
|
})),
|
|
662
|
-
...state === "locked" ? { guidance:
|
|
684
|
+
...state === "locked" ? { guidance: `This existing wallet is deny-all. Review its immutable role, then run: fased wallet policy activate-role-baseline --wallet-id ${walletId} --role ${policy.role} --confirm` } : {}
|
|
663
685
|
};
|
|
664
686
|
} catch {
|
|
665
687
|
return {
|
|
@@ -935,20 +957,20 @@ async function fetchSolanaLamportsViaRpc(params) {
|
|
|
935
957
|
if (!rpcUrl || !address) {
|
|
936
958
|
return null;
|
|
937
959
|
}
|
|
938
|
-
|
|
939
|
-
const timeout = setTimeout(() => controller.abort(), Math.max(250, params.timeoutMs));
|
|
960
|
+
let release;
|
|
940
961
|
try {
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
962
|
+
const guarded = await fetchPinnedSolanaRpcRead({
|
|
963
|
+
rpcUrl,
|
|
964
|
+
timeoutMs: params.timeoutMs,
|
|
944
965
|
body: JSON.stringify({
|
|
945
966
|
jsonrpc: "2.0",
|
|
946
967
|
id: "wallet-balance-fallback",
|
|
947
968
|
method: "getBalance",
|
|
948
969
|
params: [address]
|
|
949
|
-
})
|
|
950
|
-
signal: controller.signal
|
|
970
|
+
})
|
|
951
971
|
});
|
|
972
|
+
release = guarded.release;
|
|
973
|
+
const response = guarded.response;
|
|
952
974
|
if (!response.ok) {
|
|
953
975
|
recordWalletGatewayRpcMethod("direct.getBalance", "failure");
|
|
954
976
|
return null;
|
|
@@ -962,7 +984,7 @@ async function fetchSolanaLamportsViaRpc(params) {
|
|
|
962
984
|
recordWalletGatewayRpcMethod("direct.getBalance", "failure");
|
|
963
985
|
return null;
|
|
964
986
|
} finally {
|
|
965
|
-
|
|
987
|
+
await release?.();
|
|
966
988
|
}
|
|
967
989
|
}
|
|
968
990
|
function resolveWalletProbeTimeoutMs(env) {
|
|
@@ -1004,11 +1026,18 @@ function resolveMiningAgentWalletConflict(walletId) {
|
|
|
1004
1026
|
return null;
|
|
1005
1027
|
}
|
|
1006
1028
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
1007
|
-
if (activeMiningWalletId
|
|
1008
|
-
return
|
|
1029
|
+
if (activeMiningWalletId && activeMiningWalletId !== normalizedWalletId) {
|
|
1030
|
+
return `SAT Mining already uses ${activeMiningWalletId}. Archive that singleton wallet before attaching a replacement.`;
|
|
1009
1031
|
}
|
|
1010
1032
|
const registry = readWalletProviderRegistry(process.env);
|
|
1011
1033
|
const wallet = registry.wallets.find((entry) => entry.id === normalizedWalletId);
|
|
1034
|
+
const otherMiningWallet = registry.wallets.find((entry) => entry.id !== normalizedWalletId && resolveWalletUserRole(entry) === "mining");
|
|
1035
|
+
if (otherMiningWallet) {
|
|
1036
|
+
return `SAT Mining already has the singleton wallet ${otherMiningWallet.id}. Archive it before attaching a replacement.`;
|
|
1037
|
+
}
|
|
1038
|
+
if (!wallet) {
|
|
1039
|
+
return "SAT Mining requires an existing dedicated Mining wallet.";
|
|
1040
|
+
}
|
|
1012
1041
|
const purpose = resolveWalletUserRole(wallet);
|
|
1013
1042
|
if (normalizedWalletId === registry.defaultWalletId || purpose === "agent") {
|
|
1014
1043
|
return "SAT Mining must use a dedicated Mining wallet. Create a new Mining wallet instead of reusing an Agent wallet.";
|
|
@@ -1288,9 +1317,9 @@ async function checkSolanaAtaReadiness(address, env) {
|
|
|
1288
1317
|
}
|
|
1289
1318
|
try {
|
|
1290
1319
|
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1293
|
-
|
|
1320
|
+
const guarded = await fetchPinnedSolanaRpcRead({
|
|
1321
|
+
rpcUrl,
|
|
1322
|
+
timeoutMs: 1e4,
|
|
1294
1323
|
body: JSON.stringify({
|
|
1295
1324
|
jsonrpc: "2.0",
|
|
1296
1325
|
id: 1,
|
|
@@ -1302,15 +1331,19 @@ async function checkSolanaAtaReadiness(address, env) {
|
|
|
1302
1331
|
]
|
|
1303
1332
|
})
|
|
1304
1333
|
});
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1334
|
+
try {
|
|
1335
|
+
if (!guarded.response.ok) {
|
|
1336
|
+
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", "failure");
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
const payload = await guarded.response.json();
|
|
1340
|
+
const accounts = payload?.result?.value;
|
|
1341
|
+
const ok = Array.isArray(accounts);
|
|
1342
|
+
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", ok ? "success" : "failure");
|
|
1343
|
+
return ok && accounts.length > 0;
|
|
1344
|
+
} finally {
|
|
1345
|
+
await guarded.release();
|
|
1308
1346
|
}
|
|
1309
|
-
const payload = await response.json();
|
|
1310
|
-
const accounts = payload?.result?.value;
|
|
1311
|
-
const ok = Array.isArray(accounts);
|
|
1312
|
-
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", ok ? "success" : "failure");
|
|
1313
|
-
return ok && accounts.length > 0;
|
|
1314
1347
|
} catch {
|
|
1315
1348
|
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", "failure");
|
|
1316
1349
|
return false;
|
|
@@ -3065,7 +3098,20 @@ function createGatewayHttpServer(opts) {
|
|
|
3065
3098
|
const directLocalRequest = !tailscaleProxyConfigured && isDirectLoopbackRequest(req, trustedProxies);
|
|
3066
3099
|
const ensureWalletApiAuthorized = async () => {
|
|
3067
3100
|
if (directLocalRequest) {
|
|
3068
|
-
|
|
3101
|
+
const requestOrigin = String(getHeader(req, "origin") ?? "").trim();
|
|
3102
|
+
if (!requestOrigin || isLoopbackBrowserOrigin(requestOrigin)) {
|
|
3103
|
+
return true;
|
|
3104
|
+
}
|
|
3105
|
+
if (!loopbackCorsApplied) {
|
|
3106
|
+
sendLoginResponse(403, {
|
|
3107
|
+
ok: false,
|
|
3108
|
+
error: {
|
|
3109
|
+
code: "forbidden_origin",
|
|
3110
|
+
message: "cross-origin browser requests are not allowed on the loopback wallet API"
|
|
3111
|
+
}
|
|
3112
|
+
});
|
|
3113
|
+
return false;
|
|
3114
|
+
}
|
|
3069
3115
|
}
|
|
3070
3116
|
let authorized = false;
|
|
3071
3117
|
const bearer = getBearerToken(req);
|
|
@@ -4476,24 +4522,24 @@ function createGatewayHttpServer(opts) {
|
|
|
4476
4522
|
const requestedWalletId = typeof payload.walletId === "string" ? payload.walletId.trim() : "";
|
|
4477
4523
|
const roleProvided = Object.prototype.hasOwnProperty.call(payload, "role");
|
|
4478
4524
|
const normalizedRole = roleProvided ? normalizeWalletUserRole(payload.role) : undefined;
|
|
4479
|
-
const requestedRole = normalizedRole === "agent" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4525
|
+
const requestedRole = normalizedRole === "agent" || normalizedRole === "mining" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4480
4526
|
if (roleProvided && !requestedRole) {
|
|
4481
4527
|
sendLoginResponse(400, {
|
|
4482
4528
|
ok: false,
|
|
4483
4529
|
error: {
|
|
4484
4530
|
code: "invalid_wallet_role",
|
|
4485
|
-
message: "role must be agent or vault"
|
|
4531
|
+
message: "role must be agent, mining, or vault"
|
|
4486
4532
|
}
|
|
4487
4533
|
});
|
|
4488
4534
|
return;
|
|
4489
4535
|
}
|
|
4490
4536
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
4491
|
-
if (requestedRole &&
|
|
4537
|
+
if (requestedRole === "mining" && activeMiningWalletId && requestedWalletId !== activeMiningWalletId) {
|
|
4492
4538
|
sendLoginResponse(409, {
|
|
4493
4539
|
ok: false,
|
|
4494
4540
|
error: {
|
|
4495
4541
|
code: "wallet_in_use",
|
|
4496
|
-
message:
|
|
4542
|
+
message: `Mining already uses the singleton wallet ${activeMiningWalletId}; use the reviewed Replace/Archive flow instead of creating a second Mining wallet`
|
|
4497
4543
|
}
|
|
4498
4544
|
});
|
|
4499
4545
|
return;
|
|
@@ -4581,6 +4627,16 @@ function createGatewayHttpServer(opts) {
|
|
|
4581
4627
|
});
|
|
4582
4628
|
return;
|
|
4583
4629
|
}
|
|
4630
|
+
if (!requestedRole) {
|
|
4631
|
+
sendLoginResponse(400, {
|
|
4632
|
+
ok: false,
|
|
4633
|
+
error: {
|
|
4634
|
+
code: "invalid_wallet_role",
|
|
4635
|
+
message: "choose agent, mining, or vault; the native signer never infers a role"
|
|
4636
|
+
}
|
|
4637
|
+
});
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4584
4640
|
const chain = inferLocalSignerCreateChain({
|
|
4585
4641
|
payloadChain: payload.chain,
|
|
4586
4642
|
walletId: requestedWalletId,
|
|
@@ -4597,18 +4653,26 @@ function createGatewayHttpServer(opts) {
|
|
|
4597
4653
|
});
|
|
4598
4654
|
return;
|
|
4599
4655
|
}
|
|
4656
|
+
const rpcUrl = typeof payload.rpcUrl === "string" ? payload.rpcUrl.trim() : "";
|
|
4657
|
+
if (!rpcUrl) {
|
|
4658
|
+
sendLoginResponse(400, {
|
|
4659
|
+
ok: false,
|
|
4660
|
+
error: {
|
|
4661
|
+
code: "invalid_request",
|
|
4662
|
+
message: "one primary Solana RPC URL is required for native signer wallet creation"
|
|
4663
|
+
}
|
|
4664
|
+
});
|
|
4665
|
+
return;
|
|
4666
|
+
}
|
|
4600
4667
|
try {
|
|
4601
|
-
const effectiveEnv = {
|
|
4602
|
-
...process.env,
|
|
4603
|
-
...cfg.env?.vars
|
|
4604
|
-
};
|
|
4605
4668
|
await walletSetupCommand(silentWalletSetupRuntime, {
|
|
4606
4669
|
mode: "local-signer-create",
|
|
4607
4670
|
chain,
|
|
4608
4671
|
walletId: requestedWalletId,
|
|
4609
4672
|
walletName,
|
|
4610
|
-
rpcUrl
|
|
4673
|
+
rpcUrl,
|
|
4611
4674
|
role: requestedRole,
|
|
4675
|
+
force: true,
|
|
4612
4676
|
nonInteractive: true,
|
|
4613
4677
|
noSignerHints: true,
|
|
4614
4678
|
noDoctor: true
|
|
@@ -4738,13 +4802,15 @@ function createGatewayHttpServer(opts) {
|
|
|
4738
4802
|
const name = typeof payload.name === "string" && payload.name.trim() ? payload.name.trim() : undefined;
|
|
4739
4803
|
const roleProvided = Object.prototype.hasOwnProperty.call(payload, "role");
|
|
4740
4804
|
const normalizedRole = roleProvided ? normalizeWalletUserRole(payload.role) : undefined;
|
|
4741
|
-
const requestedRole = normalizedRole === "agent" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4742
|
-
|
|
4805
|
+
const requestedRole = normalizedRole === "agent" || normalizedRole === "mining" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4806
|
+
const rpcUrl = typeof payload.rpcUrl === "string" ? payload.rpcUrl.trim() : "";
|
|
4807
|
+
const rpcProvided = Object.prototype.hasOwnProperty.call(payload, "rpcUrl");
|
|
4808
|
+
if (!walletId || !name && !roleProvided && !rpcProvided) {
|
|
4743
4809
|
sendLoginResponse(400, {
|
|
4744
4810
|
ok: false,
|
|
4745
4811
|
error: {
|
|
4746
4812
|
code: "invalid_request",
|
|
4747
|
-
message: "walletId and
|
|
4813
|
+
message: "walletId and role or rpcUrl are required"
|
|
4748
4814
|
}
|
|
4749
4815
|
});
|
|
4750
4816
|
return;
|
|
@@ -4754,7 +4820,7 @@ function createGatewayHttpServer(opts) {
|
|
|
4754
4820
|
ok: false,
|
|
4755
4821
|
error: {
|
|
4756
4822
|
code: "invalid_wallet_role",
|
|
4757
|
-
message: "role must be agent or vault"
|
|
4823
|
+
message: "role must be agent, mining, or vault"
|
|
4758
4824
|
}
|
|
4759
4825
|
});
|
|
4760
4826
|
return;
|
|
@@ -4781,13 +4847,117 @@ function createGatewayHttpServer(opts) {
|
|
|
4781
4847
|
});
|
|
4782
4848
|
return;
|
|
4783
4849
|
}
|
|
4850
|
+
if (rpcProvided) {
|
|
4851
|
+
if (!rpcUrl) {
|
|
4852
|
+
sendLoginResponse(400, {
|
|
4853
|
+
ok: false,
|
|
4854
|
+
error: {
|
|
4855
|
+
code: "invalid_request",
|
|
4856
|
+
message: "rpcUrl must be a non-empty primary Solana RPC URL"
|
|
4857
|
+
}
|
|
4858
|
+
});
|
|
4859
|
+
return;
|
|
4860
|
+
}
|
|
4861
|
+
if (existing.providerId !== "local-socket-signer") {
|
|
4862
|
+
sendLoginResponse(409, {
|
|
4863
|
+
ok: false,
|
|
4864
|
+
error: {
|
|
4865
|
+
code: "invalid_provider",
|
|
4866
|
+
message: "primary RPC editing is available only for native signer wallets"
|
|
4867
|
+
}
|
|
4868
|
+
});
|
|
4869
|
+
return;
|
|
4870
|
+
}
|
|
4871
|
+
const cfg = loadConfig();
|
|
4872
|
+
if (!ensureWalletApprovalAuthorized({
|
|
4873
|
+
operation: "wallet.network",
|
|
4874
|
+
cfg
|
|
4875
|
+
})) {
|
|
4876
|
+
return;
|
|
4877
|
+
}
|
|
4878
|
+
try {
|
|
4879
|
+
const effectiveEnv = {
|
|
4880
|
+
...process.env,
|
|
4881
|
+
...cfg.env?.vars
|
|
4882
|
+
};
|
|
4883
|
+
const signerWalletId = resolveNativeSignerWalletId(existing);
|
|
4884
|
+
const network = await configureSignerOwnedWalletNetwork({
|
|
4885
|
+
walletId: signerWalletId,
|
|
4886
|
+
primaryRpcUrl: rpcUrl,
|
|
4887
|
+
env: effectiveEnv,
|
|
4888
|
+
socketPath: resolveLocalSignerSocketPath(effectiveEnv)
|
|
4889
|
+
});
|
|
4890
|
+
const suffix = normalizeWalletIdForEnvSuffix(walletId)?.toUpperCase();
|
|
4891
|
+
const rpcKey = suffix ? `FASED_WALLET_SOLANA_RPC_URL__${suffix}` : "FASED_WALLET_SOLANA_RPC_URL";
|
|
4892
|
+
const configUpdate = await updateWalletConfig({
|
|
4893
|
+
env: effectiveEnv,
|
|
4894
|
+
mutate: (next) => {
|
|
4895
|
+
next.env = {
|
|
4896
|
+
...next.env,
|
|
4897
|
+
vars: {
|
|
4898
|
+
...next.env?.vars,
|
|
4899
|
+
[rpcKey]: rpcUrl
|
|
4900
|
+
}
|
|
4901
|
+
};
|
|
4902
|
+
}
|
|
4903
|
+
});
|
|
4904
|
+
if (!configUpdate.ok) {
|
|
4905
|
+
throw new Error(`signer accepted network version ${network.version}, but app configuration persistence failed: ${configUpdate.message}`);
|
|
4906
|
+
}
|
|
4907
|
+
upsertNamedWallet({
|
|
4908
|
+
walletId: existing.id,
|
|
4909
|
+
name: existing.name,
|
|
4910
|
+
providerId: existing.providerId,
|
|
4911
|
+
addresses: existing.addresses,
|
|
4912
|
+
metadata: {
|
|
4913
|
+
...existing.metadata,
|
|
4914
|
+
networkHash: network.hash,
|
|
4915
|
+
networkVersion: network.version,
|
|
4916
|
+
networkReady: network.ready
|
|
4917
|
+
},
|
|
4918
|
+
env: process.env
|
|
4919
|
+
});
|
|
4920
|
+
appendWalletAuditEntry({
|
|
4921
|
+
action: "wallet_rpc_updated",
|
|
4922
|
+
actor: "control-ui",
|
|
4923
|
+
details: {
|
|
4924
|
+
walletId,
|
|
4925
|
+
networkVersion: network.version,
|
|
4926
|
+
networkReady: network.ready
|
|
4927
|
+
},
|
|
4928
|
+
env: process.env
|
|
4929
|
+
});
|
|
4930
|
+
} catch (err) {
|
|
4931
|
+
sendLoginResponse(502, {
|
|
4932
|
+
ok: false,
|
|
4933
|
+
error: {
|
|
4934
|
+
code: "wallet_rpc_update_failed",
|
|
4935
|
+
message: err instanceof Error ? err.message : String(err)
|
|
4936
|
+
}
|
|
4937
|
+
});
|
|
4938
|
+
return;
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4784
4941
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
4785
|
-
if (requestedRole
|
|
4942
|
+
if (requestedRole === "mining") {
|
|
4943
|
+
const miningConflict = resolveMiningAgentWalletConflict(walletId);
|
|
4944
|
+
if (miningConflict) {
|
|
4945
|
+
sendLoginResponse(409, {
|
|
4946
|
+
ok: false,
|
|
4947
|
+
error: {
|
|
4948
|
+
code: "wallet_in_use",
|
|
4949
|
+
message: miningConflict
|
|
4950
|
+
}
|
|
4951
|
+
});
|
|
4952
|
+
return;
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
if (requestedRole && requestedRole !== "mining" && walletId === activeMiningWalletId) {
|
|
4786
4956
|
sendLoginResponse(409, {
|
|
4787
4957
|
ok: false,
|
|
4788
4958
|
error: {
|
|
4789
4959
|
code: "wallet_in_use",
|
|
4790
|
-
message: "walletId is the singleton SAT
|
|
4960
|
+
message: "walletId is the singleton SAT Mining wallet; use the guarded Archive/Replace flow before creating a wallet with a different role"
|
|
4791
4961
|
}
|
|
4792
4962
|
});
|
|
4793
4963
|
return;
|
|
@@ -4806,7 +4976,7 @@ function createGatewayHttpServer(opts) {
|
|
|
4806
4976
|
ok: false,
|
|
4807
4977
|
error: {
|
|
4808
4978
|
code: "signer_wallet_role_immutable",
|
|
4809
|
-
message: `The native signer owns this wallet as role=${signerPolicy.role}; the Gateway cannot change it to ${requestedRole}. ` + "Create a new signer-owned wallet with the required locked role
|
|
4979
|
+
message: `The native signer owns this wallet as role=${signerPolicy.role}; the Gateway cannot change it to ${requestedRole}. ` + "Create a new signer-owned wallet with the required locked role, then use the guarded Archive/Replace flow for the old wallet."
|
|
4810
4980
|
}
|
|
4811
4981
|
});
|
|
4812
4982
|
return;
|
|
@@ -4863,6 +5033,8 @@ function createGatewayHttpServer(opts) {
|
|
|
4863
5033
|
}
|
|
4864
5034
|
const payload = body.value ?? {};
|
|
4865
5035
|
const walletId = typeof payload.walletId === "string" ? payload.walletId.trim() : "";
|
|
5036
|
+
const archiveRequested = payload.archive === true;
|
|
5037
|
+
const archiveConfirmation = typeof payload.confirmWalletId === "string" ? payload.confirmWalletId.trim() : "";
|
|
4866
5038
|
if (!walletId) {
|
|
4867
5039
|
sendLoginResponse(400, {
|
|
4868
5040
|
ok: false,
|
|
@@ -4873,13 +5045,23 @@ function createGatewayHttpServer(opts) {
|
|
|
4873
5045
|
});
|
|
4874
5046
|
return;
|
|
4875
5047
|
}
|
|
5048
|
+
if (archiveRequested && archiveConfirmation !== walletId) {
|
|
5049
|
+
sendLoginResponse(400, {
|
|
5050
|
+
ok: false,
|
|
5051
|
+
error: {
|
|
5052
|
+
code: "archive_confirmation_required",
|
|
5053
|
+
message: "confirmWalletId must exactly match walletId"
|
|
5054
|
+
}
|
|
5055
|
+
});
|
|
5056
|
+
return;
|
|
5057
|
+
}
|
|
4876
5058
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
4877
|
-
if (activeMiningWalletId === walletId) {
|
|
5059
|
+
if (activeMiningWalletId === walletId && !archiveRequested) {
|
|
4878
5060
|
sendLoginResponse(409, {
|
|
4879
5061
|
ok: false,
|
|
4880
5062
|
error: {
|
|
4881
5063
|
code: "wallet_in_use",
|
|
4882
|
-
message: "walletId is the singleton SAT
|
|
5064
|
+
message: "walletId is the singleton SAT Mining wallet; request the guarded Archive flow instead of ordinary delete"
|
|
4883
5065
|
}
|
|
4884
5066
|
});
|
|
4885
5067
|
return;
|
|
@@ -4896,6 +5078,16 @@ function createGatewayHttpServer(opts) {
|
|
|
4896
5078
|
});
|
|
4897
5079
|
return;
|
|
4898
5080
|
}
|
|
5081
|
+
if (resolveWalletUserRole(existing) === "mining") {
|
|
5082
|
+
sendLoginResponse(409, {
|
|
5083
|
+
ok: false,
|
|
5084
|
+
error: {
|
|
5085
|
+
code: "mining_retirement_required",
|
|
5086
|
+
message: "Mining wallets cannot be deleted directly; use Retire and replace Mining wallet so signer acknowledgement precedes registry detachment"
|
|
5087
|
+
}
|
|
5088
|
+
});
|
|
5089
|
+
return;
|
|
5090
|
+
}
|
|
4899
5091
|
const deletionSafety = checkNamedWalletDeletionSafety({
|
|
4900
5092
|
walletId,
|
|
4901
5093
|
env: process.env
|
|
@@ -4911,6 +5103,88 @@ function createGatewayHttpServer(opts) {
|
|
|
4911
5103
|
});
|
|
4912
5104
|
return;
|
|
4913
5105
|
}
|
|
5106
|
+
if (existing.providerId === "local-socket-signer" && archiveRequested) {
|
|
5107
|
+
const cfg = loadConfig();
|
|
5108
|
+
if (!ensureWalletApprovalAuthorized({
|
|
5109
|
+
operation: "wallet.archive",
|
|
5110
|
+
cfg
|
|
5111
|
+
})) {
|
|
5112
|
+
return;
|
|
5113
|
+
}
|
|
5114
|
+
let archivedPolicy;
|
|
5115
|
+
try {
|
|
5116
|
+
const effectiveEnv = {
|
|
5117
|
+
...process.env,
|
|
5118
|
+
...cfg.env?.vars
|
|
5119
|
+
};
|
|
5120
|
+
archivedPolicy = await lockSignerOwnedWalletForArchive({
|
|
5121
|
+
wallet: existing,
|
|
5122
|
+
socketPath: resolveLocalSignerSocketPath(effectiveEnv)
|
|
5123
|
+
});
|
|
5124
|
+
const federationWalletId = resolveFederationBondDefaultWalletId(cfg);
|
|
5125
|
+
const suffix = normalizeWalletIdForEnvSuffix(walletId)?.toUpperCase();
|
|
5126
|
+
const rpcKey = suffix ? `FASED_WALLET_SOLANA_RPC_URL__${suffix}` : "FASED_WALLET_SOLANA_RPC_URL";
|
|
5127
|
+
const updated = await updateWalletConfig({
|
|
5128
|
+
env: effectiveEnv,
|
|
5129
|
+
mutate: (next) => {
|
|
5130
|
+
if (next.env?.vars) {
|
|
5131
|
+
delete next.env.vars[rpcKey];
|
|
5132
|
+
}
|
|
5133
|
+
const currentEntry = next.plugins?.entries?.["sat-mining"];
|
|
5134
|
+
const currentSatConfig = currentEntry?.config && typeof currentEntry.config === "object" && !Array.isArray(currentEntry.config) ? { ...currentEntry.config } : {};
|
|
5135
|
+
if (currentSatConfig.walletId === walletId) {
|
|
5136
|
+
delete currentSatConfig.walletId;
|
|
5137
|
+
next.plugins = {
|
|
5138
|
+
...next.plugins,
|
|
5139
|
+
entries: {
|
|
5140
|
+
...next.plugins?.entries,
|
|
5141
|
+
"sat-mining": {
|
|
5142
|
+
enabled: true,
|
|
5143
|
+
...currentEntry,
|
|
5144
|
+
config: currentSatConfig
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
};
|
|
5148
|
+
}
|
|
5149
|
+
if (federationWalletId === walletId) {
|
|
5150
|
+
applyFederationBondWalletConfig(next, null);
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
5153
|
+
});
|
|
5154
|
+
if (!updated.ok) {
|
|
5155
|
+
throw new Error(`signer locked the wallet, but attachment cleanup failed: ${updated.message}`);
|
|
5156
|
+
}
|
|
5157
|
+
} catch (err) {
|
|
5158
|
+
sendLoginResponse(502, {
|
|
5159
|
+
ok: false,
|
|
5160
|
+
error: {
|
|
5161
|
+
code: "wallet_archive_failed",
|
|
5162
|
+
message: err instanceof Error ? err.message : String(err)
|
|
5163
|
+
}
|
|
5164
|
+
});
|
|
5165
|
+
return;
|
|
5166
|
+
}
|
|
5167
|
+
const removed = deleteNamedWallet({
|
|
5168
|
+
walletId,
|
|
5169
|
+
env: process.env
|
|
5170
|
+
});
|
|
5171
|
+
appendWalletAuditEntry({
|
|
5172
|
+
action: "wallet_archived",
|
|
5173
|
+
actor: "control-ui",
|
|
5174
|
+
details: {
|
|
5175
|
+
walletId,
|
|
5176
|
+
signerWalletId: archivedPolicy.walletId,
|
|
5177
|
+
denyAllPolicyVersion: archivedPolicy.version
|
|
5178
|
+
},
|
|
5179
|
+
env: process.env
|
|
5180
|
+
});
|
|
5181
|
+
sendLoginResponse(200, {
|
|
5182
|
+
ok: true,
|
|
5183
|
+
removed: removed.removed,
|
|
5184
|
+
archived: true
|
|
5185
|
+
});
|
|
5186
|
+
return;
|
|
5187
|
+
}
|
|
4914
5188
|
if (existing.providerId === "local-socket-signer" || existing.providerId === "embedded-keystore" || existing.metadata?.selfHosted === true) {
|
|
4915
5189
|
sendLoginResponse(409, {
|
|
4916
5190
|
ok: false,
|
|
@@ -4943,6 +5217,44 @@ function createGatewayHttpServer(opts) {
|
|
|
4943
5217
|
});
|
|
4944
5218
|
return;
|
|
4945
5219
|
}
|
|
5220
|
+
if (requestPath === "/api/wallet/receive-qr") {
|
|
5221
|
+
if (!await ensureWalletApiAuthorized()) {
|
|
5222
|
+
return;
|
|
5223
|
+
}
|
|
5224
|
+
if (req.method !== "GET") {
|
|
5225
|
+
res.statusCode = 405;
|
|
5226
|
+
res.setHeader("Allow", "GET");
|
|
5227
|
+
sendLoginResponse(405, {
|
|
5228
|
+
ok: false,
|
|
5229
|
+
error: {
|
|
5230
|
+
code: "method_not_allowed",
|
|
5231
|
+
message: "method must be GET"
|
|
5232
|
+
}
|
|
5233
|
+
});
|
|
5234
|
+
return;
|
|
5235
|
+
}
|
|
5236
|
+
const walletId = parsedUrl.searchParams.get("walletId")?.trim() ?? "";
|
|
5237
|
+
const wallet = readWalletProviderRegistry(process.env).wallets.find((entry) => entry.id === walletId);
|
|
5238
|
+
const address = wallet?.addresses?.solana?.trim() ?? "";
|
|
5239
|
+
if (!walletId || !address || !isValidSolanaAddress(address)) {
|
|
5240
|
+
sendLoginResponse(404, {
|
|
5241
|
+
ok: false,
|
|
5242
|
+
error: {
|
|
5243
|
+
code: "wallet_address_not_found",
|
|
5244
|
+
message: "wallet address not found"
|
|
5245
|
+
}
|
|
5246
|
+
});
|
|
5247
|
+
return;
|
|
5248
|
+
}
|
|
5249
|
+
const png = Buffer.from(await renderQrPngBase64(`solana:${address}`), "base64");
|
|
5250
|
+
res.statusCode = 200;
|
|
5251
|
+
res.setHeader("Content-Type", "image/png");
|
|
5252
|
+
res.setHeader("Content-Length", String(png.byteLength));
|
|
5253
|
+
res.setHeader("Cache-Control", "private, no-store");
|
|
5254
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
5255
|
+
res.end(png);
|
|
5256
|
+
return;
|
|
5257
|
+
}
|
|
4946
5258
|
if (requestPath === "/api/wallet/assignments") {
|
|
4947
5259
|
if (!await ensureWalletApiAuthorized()) {
|
|
4948
5260
|
return;
|
|
@@ -4987,7 +5299,7 @@ function createGatewayHttpServer(opts) {
|
|
|
4987
5299
|
ok: false,
|
|
4988
5300
|
error: {
|
|
4989
5301
|
code: "wallet_in_use",
|
|
4990
|
-
message: "walletId is the singleton SAT
|
|
5302
|
+
message: "walletId is the singleton SAT Mining wallet; Archive/Replace Mining with an Agent wallet before making it the Default Agent wallet fallback"
|
|
4991
5303
|
}
|
|
4992
5304
|
});
|
|
4993
5305
|
return;
|
|
@@ -4996,12 +5308,12 @@ function createGatewayHttpServer(opts) {
|
|
|
4996
5308
|
const registry = readWalletProviderRegistry(process.env);
|
|
4997
5309
|
const wallet = registry.wallets.find((entry) => entry.id === nextDefaultWalletId);
|
|
4998
5310
|
const role = resolveWalletUserRole(wallet) ?? (registry.defaultWalletId === nextDefaultWalletId ? "agent" : undefined);
|
|
4999
|
-
if (role
|
|
5311
|
+
if (role !== "agent") {
|
|
5000
5312
|
sendLoginResponse(409, {
|
|
5001
5313
|
ok: false,
|
|
5002
5314
|
error: {
|
|
5003
5315
|
code: "wallet_purpose_locked",
|
|
5004
|
-
message: "only Agent
|
|
5316
|
+
message: "only an explicit Agent wallet can become the Default Agent wallet fallback; create or select an Agent wallet instead"
|
|
5005
5317
|
}
|
|
5006
5318
|
});
|
|
5007
5319
|
return;
|
|
@@ -5014,9 +5326,34 @@ function createGatewayHttpServer(opts) {
|
|
|
5014
5326
|
}
|
|
5015
5327
|
const agentId = typeof payload.agentId === "string" ? payload.agentId.trim() : "";
|
|
5016
5328
|
if (agentId) {
|
|
5329
|
+
const assignedWalletId = typeof payload.walletId === "string" ? payload.walletId.trim() : "";
|
|
5330
|
+
if (assignedWalletId) {
|
|
5331
|
+
const registry = readWalletProviderRegistry(process.env);
|
|
5332
|
+
const wallet = registry.wallets.find((entry) => entry.id === assignedWalletId);
|
|
5333
|
+
if (!wallet) {
|
|
5334
|
+
sendLoginResponse(404, {
|
|
5335
|
+
ok: false,
|
|
5336
|
+
error: {
|
|
5337
|
+
code: "wallet_not_found",
|
|
5338
|
+
message: "walletId does not exist"
|
|
5339
|
+
}
|
|
5340
|
+
});
|
|
5341
|
+
return;
|
|
5342
|
+
}
|
|
5343
|
+
if (resolveWalletUserRole(wallet) !== "agent") {
|
|
5344
|
+
sendLoginResponse(409, {
|
|
5345
|
+
ok: false,
|
|
5346
|
+
error: {
|
|
5347
|
+
code: "wallet_purpose_locked",
|
|
5348
|
+
message: "only an explicit Agent wallet can be assigned to an Agent"
|
|
5349
|
+
}
|
|
5350
|
+
});
|
|
5351
|
+
return;
|
|
5352
|
+
}
|
|
5353
|
+
}
|
|
5017
5354
|
setAgentWalletAssignment({
|
|
5018
5355
|
agentId,
|
|
5019
|
-
walletId:
|
|
5356
|
+
walletId: assignedWalletId || undefined,
|
|
5020
5357
|
env: process.env
|
|
5021
5358
|
});
|
|
5022
5359
|
}
|
|
@@ -5533,10 +5870,12 @@ function createGatewayHttpServer(opts) {
|
|
|
5533
5870
|
}
|
|
5534
5871
|
} };
|
|
5535
5872
|
statusPayload.wallets = registry.wallets.map((wallet) => {
|
|
5873
|
+
const liveWallet = snapshot.wallets?.find((entry) => entry.id === wallet.id);
|
|
5536
5874
|
const solana = findWalletChainEntry(snapshotAny.chainWallets?.solana, wallet.id);
|
|
5537
|
-
const readiness = {
|
|
5875
|
+
const readiness = liveWallet?.readiness ?? {
|
|
5538
5876
|
keystore: Boolean(solana?.decryptReady ?? false),
|
|
5539
|
-
rpc: Boolean(solana?.rpcConfigured)
|
|
5877
|
+
rpc: Boolean(solana?.rpcConfigured),
|
|
5878
|
+
ready: false
|
|
5540
5879
|
};
|
|
5541
5880
|
return {
|
|
5542
5881
|
id: wallet.id,
|
|
@@ -5548,7 +5887,7 @@ function createGatewayHttpServer(opts) {
|
|
|
5548
5887
|
readiness,
|
|
5549
5888
|
chains: wallet.addresses?.solana ? ["solana"] : [],
|
|
5550
5889
|
rpcConfigured: readiness.rpc,
|
|
5551
|
-
health: readiness.
|
|
5890
|
+
health: readiness.ready ? "ok" : "degraded"
|
|
5552
5891
|
};
|
|
5553
5892
|
});
|
|
5554
5893
|
if (configuredProviderId === "local-socket-signer") {
|
|
@@ -7129,7 +7468,7 @@ function createGatewayHttpServer(opts) {
|
|
|
7129
7468
|
});
|
|
7130
7469
|
return;
|
|
7131
7470
|
}
|
|
7132
|
-
if (operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7471
|
+
if (operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.network" && operation !== "wallet.archive" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7133
7472
|
sendLoginResponse(400, {
|
|
7134
7473
|
ok: false,
|
|
7135
7474
|
error: {
|
|
@@ -7263,7 +7602,7 @@ function createGatewayHttpServer(opts) {
|
|
|
7263
7602
|
const payloadRaw = body.value ?? {};
|
|
7264
7603
|
const requestId = typeof payloadRaw.requestId === "string" ? payloadRaw.requestId.trim() || undefined : undefined;
|
|
7265
7604
|
const operation = typeof payloadRaw.operation === "string" ? payloadRaw.operation.trim() || undefined : undefined;
|
|
7266
|
-
if (operation && operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7605
|
+
if (operation && operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.network" && operation !== "wallet.archive" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7267
7606
|
sendLoginResponse(400, {
|
|
7268
7607
|
ok: false,
|
|
7269
7608
|
error: {
|