@fased/fased 0.1.66 → 0.1.68
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 +18 -0
- package/README.md +4 -0
- package/config/signer-protocol-v2.json +4 -0
- 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 +33 -2
- package/dist/commands/onboard.js +0 -8
- package/dist/commands/wallet.js +485 -58
- package/dist/control-ui/assets/{app-DYxADzeH.js → app-DyPTS0oM.js} +1526 -1526
- package/dist/control-ui/assets/{index-vw_10Zeo.js → index-Cu13yYHr.js} +3 -3
- package/dist/control-ui/assets/{wallet-DvStR_AT.js → wallet-ByKBcYhm.js} +272 -188
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/gateway/server-http.js +349 -47
- package/dist/infra/runtime-guard.js +16 -0
- 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-BFLoas5R.js → audio-preflight-_FVQjR1r.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-TErs62MC.js → chunk-items-LH4uKSnh.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-BPnaDBwZ.js → config-schema-DjU_uD-6.js} +192 -94
- 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 +16 -16
- 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-FuBPk-AL.js → monitor-DUMMbG4h.js} +34 -33
- package/dist/plugin-sdk/{monitor-sW6dQdX1.js → monitor-DXIM16Hj.js} +44 -43
- package/dist/plugin-sdk/{openresponses-http-CVZq0H-P.js → openresponses-http-C8lKwta1.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-L6L6L2YF.d.ts → pairing-message-mKO92L-M.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-natjh3rm.js → pw-ai-DJ_gTc4M.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-DczkvPxn.js → runtime-dependency-nup8niQL.js} +9 -9
- package/dist/plugin-sdk/sat-runtime.d.ts +18 -2
- 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-BZISDxDd.js → slack-B-nOOLM0.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-B0aPv6Lg.js → sticker-cache-BLiId8Em.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-H3gePEn6.js → telegram-actions-1X9A32Dn.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-d1CmFAnJ.d.ts → tmp-fased-dir-BkpWlGUe.d.ts} +7 -1
- package/dist/plugin-sdk/{types-DUjYaWB2.d.ts → types-B-zL9gSv.d.ts} +1 -1
- package/dist/plugin-sdk/{types-xWjHXl1z.d.ts → types-DtCOO_hW.d.ts} +1 -1
- package/dist/plugin-sdk/{web-JwP9PAZR.js → web-BvjNyYBz.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-CIzCjXH9.d.ts → zod-schema.providers-core-BCDlgtls.d.ts} +63 -63
- package/dist/wallet/local-socket-signer-lifecycle.js +29 -1
- package/dist/wallet/local-socket-signer-protocol.js +27 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +8 -0
- package/dist/wallet/signer-network-admin.js +11 -118
- package/dist/wallet/signer-protocol-v2.generated.js +4 -0
- package/dist/wallet/solana-assets.js +9 -3
- package/dist/wallet/solana-rpc-read-fetch.js +65 -0
- package/dist/wallet/wallet-status.js +7 -0
- package/dist/web/login-qr.js +1 -1
- package/dist/wizard/onboarding.js +61 -61
- 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/fased.mjs +14 -1
- package/install.sh +16 -10
- package/package.json +6 -1
- package/scripts/fased-managed-updater.mjs +10 -2
- package/scripts/fased-signer-wallet-import-hosting.sh +78 -0
- package/scripts/install-managed-runtime.mjs +10 -7
- /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
|
@@ -292,6 +292,16 @@ const LocalSocketSignerSatLookupBindingV2Schema = Type.Object({
|
|
|
292
292
|
Type.Literal("unknown")
|
|
293
293
|
]))
|
|
294
294
|
}, { additionalProperties: false });
|
|
295
|
+
const LocalSocketSignerNetworkSummaryV2Schema = Type.Object({
|
|
296
|
+
walletId: Type.String({
|
|
297
|
+
minLength: 1,
|
|
298
|
+
maxLength: 64
|
|
299
|
+
}),
|
|
300
|
+
configured: Type.Boolean(),
|
|
301
|
+
version: Type.Integer({ minimum: 0 }),
|
|
302
|
+
hash: Type.Optional(Type.String({ pattern: "^hmac-sha256:[0-9a-f]{64}$" })),
|
|
303
|
+
ready: Type.Boolean()
|
|
304
|
+
}, { additionalProperties: false });
|
|
295
305
|
const LocalSocketSignerRequestSchema = Type.Union([
|
|
296
306
|
Type.Object({ op: Type.Literal("health") }, { additionalProperties: false }),
|
|
297
307
|
Type.Object({ op: Type.Literal("v2.capabilities") }, { additionalProperties: false }),
|
|
@@ -303,6 +313,21 @@ const LocalSocketSignerRequestSchema = Type.Union([
|
|
|
303
313
|
op: Type.Literal("v2.policy.get"),
|
|
304
314
|
walletId: Type.String()
|
|
305
315
|
}, { additionalProperties: false }),
|
|
316
|
+
Type.Object({
|
|
317
|
+
op: Type.Literal("v2.network.get"),
|
|
318
|
+
walletId: Type.String()
|
|
319
|
+
}, { additionalProperties: false }),
|
|
320
|
+
Type.Object({
|
|
321
|
+
op: Type.Literal("v2.network.bootstrap"),
|
|
322
|
+
walletId: Type.String(),
|
|
323
|
+
request: Type.Object({
|
|
324
|
+
expectedVersion: Type.Integer({ minimum: 0 }),
|
|
325
|
+
primaryRpcUrl: Type.String({
|
|
326
|
+
minLength: 1,
|
|
327
|
+
maxLength: 2048
|
|
328
|
+
})
|
|
329
|
+
}, { additionalProperties: false })
|
|
330
|
+
}, { additionalProperties: false }),
|
|
306
331
|
Type.Object({
|
|
307
332
|
op: Type.Literal("v2.policy.put"),
|
|
308
333
|
walletId: Type.String(),
|
|
@@ -665,6 +690,8 @@ function validateLocalSocketSignerResult(op, result) {
|
|
|
665
690
|
case "health":
|
|
666
691
|
case "v2.capabilities": return Value.Check(LocalSocketSignerHealthResultSchema, result);
|
|
667
692
|
case "v2.jupiter.trigger.history": return Value.Check(LocalSocketSignerJupiterTriggerHistoryV2Schema, result);
|
|
693
|
+
case "v2.network.get":
|
|
694
|
+
case "v2.network.bootstrap": return Value.Check(LocalSocketSignerNetworkSummaryV2Schema, result);
|
|
668
695
|
case "v2.policy.get":
|
|
669
696
|
case "v2.policy.put":
|
|
670
697
|
case "v2.policy.tighten": return Value.Check(LocalSocketSignerPolicyV2Schema, result);
|
|
@@ -14,6 +14,8 @@ const REQUIRED_PROTOCOL_V2_FEATURES = SIGNER_PROTOCOL_V2_REQUIRED_CLIENT_FEATURE
|
|
|
14
14
|
const SIGNER_SOCKET_TIMEOUT_MS = {
|
|
15
15
|
health: 2e3,
|
|
16
16
|
"v2.capabilities": 2e3,
|
|
17
|
+
"v2.network.get": 15e3,
|
|
18
|
+
"v2.network.bootstrap": 3e4,
|
|
17
19
|
"v2.jupiter.trigger.history": 3e4,
|
|
18
20
|
"v2.policy.get": 5e3,
|
|
19
21
|
"v2.policy.put": 5e3,
|
|
@@ -227,6 +229,12 @@ var LocalSocketSignerAdapter = class {
|
|
|
227
229
|
provider: this.id,
|
|
228
230
|
configured: true,
|
|
229
231
|
checkedAt: new Date().toISOString(),
|
|
232
|
+
...details.webAuthn ? { nativeSignerApproval: {
|
|
233
|
+
configured: details.webAuthn.configured,
|
|
234
|
+
ready: details.webAuthn.ready,
|
|
235
|
+
credentialCount: details.webAuthn.credentialCount,
|
|
236
|
+
credentialVersion: details.webAuthn.credentialVersion
|
|
237
|
+
} } : {},
|
|
230
238
|
details: [
|
|
231
239
|
details?.details ?? "",
|
|
232
240
|
...!details?.details ? [
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { spawnSync } from "node:child_process";
|
|
1
|
+
import { resolveLocalSignerSocketPath } from "./wallet-runtime-config.js";
|
|
2
|
+
import { configureSignerOwnedWalletPrimaryRpc } from "./local-socket-signer-lifecycle.js";
|
|
4
3
|
|
|
5
4
|
//#region src/wallet/signer-network-admin.ts
|
|
6
|
-
const NETWORK_ADMIN_TIMEOUT_MS = 3e4;
|
|
7
|
-
const NETWORK_ADMIN_MAX_OUTPUT_BYTES = 256 * 1024;
|
|
8
5
|
function canonicalSignerWalletId(raw) {
|
|
9
6
|
const normalized = raw.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
10
7
|
return normalized || "default";
|
|
@@ -47,62 +44,7 @@ function parseSignerNetworkSummary(raw, expectedWalletId) {
|
|
|
47
44
|
ready: record.ready
|
|
48
45
|
};
|
|
49
46
|
}
|
|
50
|
-
function
|
|
51
|
-
let value = raw;
|
|
52
|
-
for (const secret of secrets.filter(Boolean).toSorted((a, b) => b.length - a.length)) {
|
|
53
|
-
value = value.split(secret).join("[redacted-rpc-url]");
|
|
54
|
-
}
|
|
55
|
-
value = value.replace(/https?:\/\/[^\s"'<>]+/gi, "[redacted-rpc-url]");
|
|
56
|
-
value = value.replace(/\b(api[_-]?key|access[_-]?token|token|key)=([^\s&"']+)/gi, "$1=[redacted]");
|
|
57
|
-
return value.trim().slice(0, 2e3) || "signer network administration failed";
|
|
58
|
-
}
|
|
59
|
-
function signerAdminEnvironment(env) {
|
|
60
|
-
const out = {};
|
|
61
|
-
for (const key of [
|
|
62
|
-
"HOME",
|
|
63
|
-
"PATH",
|
|
64
|
-
"TMPDIR",
|
|
65
|
-
"LANG",
|
|
66
|
-
"LC_ALL",
|
|
67
|
-
"TZ"
|
|
68
|
-
]) {
|
|
69
|
-
const value = String(env[key] ?? "").trim();
|
|
70
|
-
if (value) {
|
|
71
|
-
out[key] = value;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return out;
|
|
75
|
-
}
|
|
76
|
-
function runSignerAdmin(params) {
|
|
77
|
-
const child = spawnSync(params.command, params.args, {
|
|
78
|
-
input: params.input,
|
|
79
|
-
env: params.env,
|
|
80
|
-
encoding: "utf8",
|
|
81
|
-
timeout: NETWORK_ADMIN_TIMEOUT_MS,
|
|
82
|
-
maxBuffer: NETWORK_ADMIN_MAX_OUTPUT_BYTES,
|
|
83
|
-
stdio: [
|
|
84
|
-
"pipe",
|
|
85
|
-
"pipe",
|
|
86
|
-
"pipe"
|
|
87
|
-
]
|
|
88
|
-
});
|
|
89
|
-
if (child.error || child.status !== 0) {
|
|
90
|
-
const detail = [
|
|
91
|
-
child.stderr,
|
|
92
|
-
child.stdout,
|
|
93
|
-
child.error?.message
|
|
94
|
-
].filter((part) => typeof part === "string" && part.trim().length > 0).join("\n");
|
|
95
|
-
throw new Error(redactSignerNetworkError(detail, params.secrets));
|
|
96
|
-
}
|
|
97
|
-
return child.stdout;
|
|
98
|
-
}
|
|
99
|
-
function assertReadyNetworkSummary(summary, previousVersion) {
|
|
100
|
-
if (!summary.configured || !summary.ready || !summary.hash || summary.version !== previousVersion + 1) {
|
|
101
|
-
throw new Error("signer network update did not acknowledge the exact next ready version");
|
|
102
|
-
}
|
|
103
|
-
return summary;
|
|
104
|
-
}
|
|
105
|
-
function configureSignerOwnedWalletNetwork(params) {
|
|
47
|
+
async function configureSignerOwnedWalletNetwork(params) {
|
|
106
48
|
const env = params.env ?? process.env;
|
|
107
49
|
const walletId = canonicalSignerWalletId(params.walletId);
|
|
108
50
|
const primaryRpcUrl = params.primaryRpcUrl.trim();
|
|
@@ -111,61 +53,14 @@ function configureSignerOwnedWalletNetwork(params) {
|
|
|
111
53
|
if (!primaryRpcUrl) {
|
|
112
54
|
throw new Error("signer-owned wallet network requires a primary RPC URL");
|
|
113
55
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
executionFallbackRpcUrl,
|
|
117
|
-
verificationRpcUrl
|
|
118
|
-
];
|
|
119
|
-
const hosting = String(env.FASED_HOST_PROFILE ?? "").trim().toLowerCase() === "hosting";
|
|
120
|
-
if (hosting) {
|
|
121
|
-
return {
|
|
122
|
-
walletId,
|
|
123
|
-
configured: false,
|
|
124
|
-
version: 0,
|
|
125
|
-
ready: false,
|
|
126
|
-
rootAdminRequired: true,
|
|
127
|
-
rootCommand: `/usr/local/sbin/fased-signer-network --wallet-id ${walletId} ` + "--network-file /root/fased-network.json"
|
|
128
|
-
};
|
|
56
|
+
if (executionFallbackRpcUrl || verificationRpcUrl) {
|
|
57
|
+
throw new Error("Normal wallet setup accepts one primary RPC. Configure an advanced execution fallback or explicit witness with the native signer admin network command.");
|
|
129
58
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
controlSocketPath,
|
|
136
|
-
"--wallet-id",
|
|
137
|
-
walletId
|
|
138
|
-
];
|
|
139
|
-
const current = parseSignerNetworkSummary(runSignerAdmin({
|
|
140
|
-
command: signerBinPath,
|
|
141
|
-
args: [
|
|
142
|
-
"admin",
|
|
143
|
-
"network",
|
|
144
|
-
"get",
|
|
145
|
-
...commonArgs
|
|
146
|
-
],
|
|
147
|
-
env: adminEnv,
|
|
148
|
-
secrets
|
|
149
|
-
}), walletId);
|
|
150
|
-
const input = `${JSON.stringify({
|
|
151
|
-
expectedVersion: current.version,
|
|
152
|
-
primaryRpcUrl,
|
|
153
|
-
...executionFallbackRpcUrl ? { executionFallbackRpcUrl } : {},
|
|
154
|
-
...verificationRpcUrl ? { verificationRpcUrl } : {}
|
|
155
|
-
})}\n`;
|
|
156
|
-
const updated = parseSignerNetworkSummary(runSignerAdmin({
|
|
157
|
-
command: signerBinPath,
|
|
158
|
-
args: [
|
|
159
|
-
"admin",
|
|
160
|
-
"network",
|
|
161
|
-
"put",
|
|
162
|
-
...commonArgs
|
|
163
|
-
],
|
|
164
|
-
input,
|
|
165
|
-
env: adminEnv,
|
|
166
|
-
secrets
|
|
167
|
-
}), walletId);
|
|
168
|
-
return assertReadyNetworkSummary(updated, current.version);
|
|
59
|
+
return configureSignerOwnedWalletPrimaryRpc({
|
|
60
|
+
socketPath: params.socketPath ?? resolveLocalSignerSocketPath(env),
|
|
61
|
+
walletId,
|
|
62
|
+
primaryRpcUrl
|
|
63
|
+
});
|
|
169
64
|
}
|
|
170
65
|
/**
|
|
171
66
|
* Hosted policy changes are deliberately unavailable to the app process. New signer-owned
|
|
@@ -181,9 +76,7 @@ function applyHostedSignerOwnedWalletPolicy(params) {
|
|
|
181
76
|
}
|
|
182
77
|
const __testing = {
|
|
183
78
|
canonicalSignerWalletId,
|
|
184
|
-
parseSignerNetworkSummary
|
|
185
|
-
redactSignerNetworkError,
|
|
186
|
-
signerAdminEnvironment
|
|
79
|
+
parseSignerNetworkSummary
|
|
187
80
|
};
|
|
188
81
|
|
|
189
82
|
//#endregion
|
|
@@ -38,6 +38,9 @@ const SIGNER_PROTOCOL_V2 = {
|
|
|
38
38
|
"signerOwnedSuccessorRotation",
|
|
39
39
|
"permanentRetiredWalletPolicies",
|
|
40
40
|
"signerOwnedRPC",
|
|
41
|
+
"applicationNetworkBootstrap",
|
|
42
|
+
"signerOwnedEncryptedRecovery",
|
|
43
|
+
"signerOwnedRawExport",
|
|
41
44
|
"typedSolanaTransactions",
|
|
42
45
|
"typedA2aPaymentMemos",
|
|
43
46
|
"typedA2aRefundMemos",
|
|
@@ -75,6 +78,7 @@ const SIGNER_PROTOCOL_V2_REQUIRED_CLIENT_FEATURES = [
|
|
|
75
78
|
"ambiguousBroadcastReconciliation",
|
|
76
79
|
"signerOwnedKeys",
|
|
77
80
|
"signerOwnedRPC",
|
|
81
|
+
"applicationNetworkBootstrap",
|
|
78
82
|
"typedSolanaTransactions",
|
|
79
83
|
"typedA2aPaymentMemos",
|
|
80
84
|
"typedA2aRefundMemos",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fetchPinnedSolanaRpcRead } from "./solana-rpc-read-fetch.js";
|
|
1
2
|
import { PublicKey } from "@solana/web3.js";
|
|
2
3
|
|
|
3
4
|
//#region src/wallet/solana-assets.ts
|
|
@@ -427,10 +428,11 @@ function formatTokenAmount(raw, decimals) {
|
|
|
427
428
|
}
|
|
428
429
|
}
|
|
429
430
|
async function fetchSolanaRpc(rpcUrl, method, params) {
|
|
431
|
+
let release;
|
|
430
432
|
try {
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
433
|
+
const guarded = await fetchPinnedSolanaRpcRead({
|
|
434
|
+
rpcUrl,
|
|
435
|
+
timeoutMs: 1e4,
|
|
434
436
|
body: JSON.stringify({
|
|
435
437
|
jsonrpc: "2.0",
|
|
436
438
|
id: 1,
|
|
@@ -438,6 +440,8 @@ async function fetchSolanaRpc(rpcUrl, method, params) {
|
|
|
438
440
|
params
|
|
439
441
|
})
|
|
440
442
|
});
|
|
443
|
+
release = guarded.release;
|
|
444
|
+
const response = guarded.response;
|
|
441
445
|
if (!response.ok) {
|
|
442
446
|
recordSolanaAssetRpcMethod(method, "failure");
|
|
443
447
|
return null;
|
|
@@ -452,6 +456,8 @@ async function fetchSolanaRpc(rpcUrl, method, params) {
|
|
|
452
456
|
} catch {
|
|
453
457
|
recordSolanaAssetRpcMethod(method, "failure");
|
|
454
458
|
return null;
|
|
459
|
+
} finally {
|
|
460
|
+
await release?.();
|
|
455
461
|
}
|
|
456
462
|
}
|
|
457
463
|
async function fetchSolanaMetadataFromMintViaRpc(params) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { closeDispatcher, createPinnedDispatcher, resolvePinnedHostnameWithPolicy } from "../infra/net/ssrf.js";
|
|
2
|
+
|
|
3
|
+
//#region src/wallet/solana-rpc-read-fetch.ts
|
|
4
|
+
function normalizeRpcHostname(hostname) {
|
|
5
|
+
const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
|
|
6
|
+
return normalized.startsWith("[") && normalized.endsWith("]") ? normalized.slice(1, -1) : normalized;
|
|
7
|
+
}
|
|
8
|
+
function isLoopbackRpcHostname(hostname) {
|
|
9
|
+
const normalized = normalizeRpcHostname(hostname);
|
|
10
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
11
|
+
}
|
|
12
|
+
function isLoopbackRpcAddress(address) {
|
|
13
|
+
const normalized = normalizeRpcHostname(address);
|
|
14
|
+
return normalized === "::1" || normalized === "0:0:0:0:0:0:0:1" || /^127(?:\.\d{1,3}){3}$/.test(normalized) || /^::ffff:127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
15
|
+
}
|
|
16
|
+
async function resolveWithTimeout(hostname, policy, timeoutMs) {
|
|
17
|
+
let timer;
|
|
18
|
+
try {
|
|
19
|
+
return await Promise.race([resolvePinnedHostnameWithPolicy(hostname, { policy }), new Promise((_resolve, reject) => {
|
|
20
|
+
timer = setTimeout(() => reject(new Error("stored Solana RPC hostname resolution timed out")), Math.max(250, timeoutMs));
|
|
21
|
+
timer.unref?.();
|
|
22
|
+
})]);
|
|
23
|
+
} finally {
|
|
24
|
+
if (timer) {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function fetchPinnedSolanaRpcRead(params) {
|
|
30
|
+
const parsed = new URL(params.rpcUrl);
|
|
31
|
+
const hostname = normalizeRpcHostname(parsed.hostname);
|
|
32
|
+
const loopback = isLoopbackRpcHostname(hostname);
|
|
33
|
+
if (!hostname || parsed.username || parsed.password || parsed.hash || parsed.protocol !== "https:" && !(parsed.protocol === "http:" && loopback)) {
|
|
34
|
+
throw new Error("stored Solana RPC URL is not safe for Gateway reads");
|
|
35
|
+
}
|
|
36
|
+
const policy = {
|
|
37
|
+
hostnameAllowlist: [hostname],
|
|
38
|
+
...loopback ? { allowPrivateNetwork: true } : {}
|
|
39
|
+
};
|
|
40
|
+
const pinned = await resolveWithTimeout(hostname, policy, params.timeoutMs);
|
|
41
|
+
if (loopback && !pinned.addresses.every(isLoopbackRpcAddress)) {
|
|
42
|
+
throw new Error("stored Local Solana RPC hostname did not resolve only to loopback addresses");
|
|
43
|
+
}
|
|
44
|
+
const dispatcher = createPinnedDispatcher(pinned);
|
|
45
|
+
try {
|
|
46
|
+
const response = await fetch(parsed.toString(), {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: { "content-type": "application/json" },
|
|
49
|
+
body: params.body,
|
|
50
|
+
redirect: "error",
|
|
51
|
+
signal: AbortSignal.timeout(Math.max(250, params.timeoutMs)),
|
|
52
|
+
dispatcher
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
response,
|
|
56
|
+
release: async () => closeDispatcher(dispatcher)
|
|
57
|
+
};
|
|
58
|
+
} catch (error) {
|
|
59
|
+
await closeDispatcher(dispatcher);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
export { fetchPinnedSolanaRpcRead };
|
|
@@ -28,6 +28,9 @@ async function readWalletStatusSnapshot(params) {
|
|
|
28
28
|
const checkedAt = new Date().toISOString();
|
|
29
29
|
let providerHealth = {
|
|
30
30
|
ok: false,
|
|
31
|
+
provider: providerId,
|
|
32
|
+
configured: false,
|
|
33
|
+
checkedAt,
|
|
31
34
|
details: "provider health probe unavailable"
|
|
32
35
|
};
|
|
33
36
|
let addresses;
|
|
@@ -53,6 +56,9 @@ async function readWalletStatusSnapshot(params) {
|
|
|
53
56
|
} catch (err) {
|
|
54
57
|
providerHealth = {
|
|
55
58
|
ok: false,
|
|
59
|
+
provider: providerId,
|
|
60
|
+
configured: false,
|
|
61
|
+
checkedAt,
|
|
56
62
|
details: walletDiagnosticErrorString(err)
|
|
57
63
|
};
|
|
58
64
|
}
|
|
@@ -90,6 +96,7 @@ async function readWalletStatusSnapshot(params) {
|
|
|
90
96
|
}
|
|
91
97
|
},
|
|
92
98
|
approvalAuth,
|
|
99
|
+
...providerHealth.nativeSignerApproval ? { nativeSignerApproval: providerHealth.nativeSignerApproval } : {},
|
|
93
100
|
addresses,
|
|
94
101
|
paths: {
|
|
95
102
|
rootDir: paths.rootDir,
|
package/dist/web/login-qr.js
CHANGED
|
@@ -5,8 +5,8 @@ import { loadConfig } from "../config/io.js";
|
|
|
5
5
|
import "../config/config.js";
|
|
6
6
|
import { logoutWeb, readWebSelfId, webAuthExists } from "./auth-store.js";
|
|
7
7
|
import { resolveWhatsAppAccount } from "./accounts.js";
|
|
8
|
-
import { createWaSocket, formatError, getStatusCode, waitForWaConnection } from "./session.js";
|
|
9
8
|
import { renderQrPngBase64 } from "./qr-image.js";
|
|
9
|
+
import { createWaSocket, formatError, getStatusCode, waitForWaConnection } from "./session.js";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { DisconnectReason } from "@whiskeysockets/baileys";
|
|
12
12
|
|
|
@@ -7,12 +7,13 @@ import { ensureAuthProfileStore } from "../agents/auth-profiles/store.js";
|
|
|
7
7
|
import { readConfigFileSnapshot, writeConfigFile } from "../config/io.js";
|
|
8
8
|
import "../config/config.js";
|
|
9
9
|
import "../agents/auth-profiles.js";
|
|
10
|
-
import { ensureWalletStateDir,
|
|
10
|
+
import { ensureWalletStateDir, resolveLocalSignerMaterialRootDir, resolveLocalSignerSocketPath } from "../wallet/wallet-runtime-config.js";
|
|
11
11
|
import { checkNamedWalletDeletionSafety, deleteNamedWallet, readWalletProviderRegistry, resolveWalletUserRole, setDefaultWallet, setNamedWalletRole, upsertNamedWallet } from "../wallet/wallet-provider-registry.js";
|
|
12
12
|
import { DEFAULT_WORKSPACE, applyWizardMetadata, ensureWorkspaceAndSessions, handleOnboardingRepair, printWizardHeader, probeGatewayReachable, summarizeExistingConfig } from "../commands/onboard-helpers.js";
|
|
13
13
|
import { configureSignerOwnedWalletNetwork } from "../wallet/signer-network-admin.js";
|
|
14
14
|
import { configureWalletForOnboarding, installSignerdBinary, resolveSignerdBinaryPath, restartLocalSocketSigner } from "./onboarding.wallet.js";
|
|
15
|
-
import { collectWalletSignerDoctorReport, walletSetupCommand } from "../commands/wallet.js";
|
|
15
|
+
import { collectWalletSignerDoctorReport, walletRecoveryExportCommand, walletSetupCommand } from "../commands/wallet.js";
|
|
16
|
+
import { lockSignerOwnedWalletForArchive } from "../wallet/local-socket-signer-archive.js";
|
|
16
17
|
import { promptAuthChoiceGrouped } from "../commands/auth-choice-prompt.js";
|
|
17
18
|
import { applyPrimaryModel, resolveAuthenticatedDefaultModel } from "../commands/model-picker.js";
|
|
18
19
|
import { logConfigUpdated } from "../config/logging.js";
|
|
@@ -26,7 +27,6 @@ import { promptCustomApiConfig } from "../commands/onboard-custom.js";
|
|
|
26
27
|
import { setupInternalHooks } from "../commands/onboard-hooks.js";
|
|
27
28
|
import { promptRemoteGatewayConfig } from "../commands/onboard-remote.js";
|
|
28
29
|
import { setupSkills } from "../commands/onboard-skills.js";
|
|
29
|
-
import { lockSignerOwnedWalletForArchive } from "../wallet/local-socket-signer-archive.js";
|
|
30
30
|
import { discoverSolanaNetworkFromRpc } from "../wallet/solana-network-discovery.js";
|
|
31
31
|
import { isHostedSecurityCapableSession } from "./host-security-capability.js";
|
|
32
32
|
import { noteBullet, noteCommand, noteHeading, noteLabel, noteStep, noteSuccess, noteWarn } from "./onboarding-note-format.js";
|
|
@@ -96,10 +96,6 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
96
96
|
}
|
|
97
97
|
return "FASED_WALLET_SOLANA_RPC_URL";
|
|
98
98
|
};
|
|
99
|
-
const executionFallbackRpcEnvKeyFor = (walletId) => {
|
|
100
|
-
const suffix = walletIdEnvSuffix(walletId);
|
|
101
|
-
return suffix ? `FASED_WALLET_SOLANA_EXECUTION_FALLBACK_RPC_URL__${suffix}` : "FASED_WALLET_SOLANA_EXECUTION_FALLBACK_RPC_URL";
|
|
102
|
-
};
|
|
103
99
|
const setConfigEnvVar = (cfg, key, value) => {
|
|
104
100
|
const vars = { ...cfg.env?.vars };
|
|
105
101
|
if (value == null || value === "") {
|
|
@@ -219,15 +215,6 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
219
215
|
process.env[rpcKey] = effectiveRpcUrl;
|
|
220
216
|
return effectiveRpcUrl;
|
|
221
217
|
};
|
|
222
|
-
const firstNonEmptyEnvValue = (...values) => {
|
|
223
|
-
for (const value of values) {
|
|
224
|
-
const normalized = String(value ?? "").trim();
|
|
225
|
-
if (normalized) {
|
|
226
|
-
return normalized;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return undefined;
|
|
230
|
-
};
|
|
231
218
|
const readSatMiningConfig = (cfg) => {
|
|
232
219
|
const config = cfg.plugins?.entries?.["sat-mining"]?.config;
|
|
233
220
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
@@ -991,28 +978,23 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
991
978
|
currentValue: configuredSolanaRpcUrl
|
|
992
979
|
});
|
|
993
980
|
let signerNetworkVersion;
|
|
994
|
-
let signerNetworkRootCommand;
|
|
995
981
|
if (targetWallet.providerId === "local-socket-signer") {
|
|
996
982
|
const effectiveEnv = {
|
|
997
983
|
...process.env,
|
|
998
984
|
...nextConfig.env?.vars,
|
|
999
985
|
FASED_HOST_PROFILE: hostProfile
|
|
1000
986
|
};
|
|
1001
|
-
const
|
|
1002
|
-
const legacyExecutionFallbackKey = walletSuffix ? `FASED_WALLET_SOLANA_WRITE_RPC_FALLBACK_URL__${walletSuffix}` : "FASED_WALLET_SOLANA_WRITE_RPC_FALLBACK_URL";
|
|
1003
|
-
const network = configureSignerOwnedWalletNetwork({
|
|
987
|
+
const network = await configureSignerOwnedWalletNetwork({
|
|
1004
988
|
walletId,
|
|
1005
989
|
primaryRpcUrl: effectiveSolanaRpcUrl,
|
|
1006
|
-
executionFallbackRpcUrl: firstNonEmptyEnvValue(effectiveEnv[executionFallbackRpcEnvKeyFor(walletId)], effectiveEnv[legacyExecutionFallbackKey]),
|
|
1007
990
|
env: effectiveEnv,
|
|
1008
|
-
|
|
991
|
+
socketPath: resolveLocalSignerSocketPath(effectiveEnv)
|
|
1009
992
|
});
|
|
1010
993
|
signerNetworkVersion = network.version;
|
|
1011
|
-
signerNetworkRootCommand = network.rootCommand;
|
|
1012
994
|
} else {
|
|
1013
995
|
await restartLocalSocketSigner(ensureWalletStateDir(process.env).rootDir);
|
|
1014
996
|
}
|
|
1015
|
-
await prompter.note([`Updated the app-side Solana RPC setting for ${targetWallet.name} (${walletId})${signerNetworkVersion ? `; signer network version ${signerNetworkVersion} is ready` : "."}
|
|
997
|
+
await prompter.note([`Updated the app-side Solana RPC setting for ${targetWallet.name} (${walletId})${signerNetworkVersion ? `; signer network version ${signerNetworkVersion} is ready` : "."}`].join("\n"), "Wallet setup");
|
|
1016
998
|
addAnotherWallet = await prompter.confirm({
|
|
1017
999
|
message: "Run another wallet setup action?",
|
|
1018
1000
|
initialValue: false
|
|
@@ -1160,8 +1142,8 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1160
1142
|
}
|
|
1161
1143
|
attemptedSelfHostedSetupThisRun = true;
|
|
1162
1144
|
const chain = "solana";
|
|
1163
|
-
const walletPurpose =
|
|
1164
|
-
message: "Wallet
|
|
1145
|
+
const walletPurpose = await prompter.select({
|
|
1146
|
+
message: "Wallet role (required)",
|
|
1165
1147
|
options: [
|
|
1166
1148
|
{
|
|
1167
1149
|
value: "agent",
|
|
@@ -1175,9 +1157,11 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1175
1157
|
value: "vault",
|
|
1176
1158
|
label: "Vault"
|
|
1177
1159
|
}
|
|
1178
|
-
]
|
|
1179
|
-
initialValue: "agent"
|
|
1160
|
+
]
|
|
1180
1161
|
});
|
|
1162
|
+
if (walletPurpose !== "agent" && walletPurpose !== "mining" && walletPurpose !== "vault") {
|
|
1163
|
+
throw new Error("Wallet role selection is required; Agent is never selected silently.");
|
|
1164
|
+
}
|
|
1181
1165
|
const selfHostedAction = await prompter.select({
|
|
1182
1166
|
message: "Wallet action",
|
|
1183
1167
|
options: [{
|
|
@@ -1193,7 +1177,7 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1193
1177
|
const existingMiningWalletId = satMiningAttachment.walletId ?? "";
|
|
1194
1178
|
const existingMiningWallet = readWalletProviderRegistry(process.env).wallets.find((wallet) => wallet.id === "mining");
|
|
1195
1179
|
if (existingMiningWalletId || existingMiningWallet) {
|
|
1196
|
-
await prompter.note([`Mining wallet already exists: ${existingMiningWalletId || "mining"}.`, "
|
|
1180
|
+
await prompter.note([`Mining wallet already exists: ${existingMiningWalletId || "mining"}.`, "Open it to continue, or use the reviewed Replace/Archive flow after mining is stopped, rewards and capital are settled, and backup/readiness checks pass."].join("\n"), "Mining");
|
|
1197
1181
|
addAnotherWallet = await prompter.confirm({
|
|
1198
1182
|
message: "Run another wallet setup action?",
|
|
1199
1183
|
initialValue: false
|
|
@@ -1201,39 +1185,31 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1201
1185
|
continue;
|
|
1202
1186
|
}
|
|
1203
1187
|
}
|
|
1204
|
-
const mode = "local-signer-create";
|
|
1188
|
+
const mode = selfHostedAction === "import" ? "local-signer-import" : "local-signer-create";
|
|
1205
1189
|
const walletIdentity = await resolveWalletIdentityForOnboarding({
|
|
1206
1190
|
flow,
|
|
1207
1191
|
purpose: walletPurpose
|
|
1208
1192
|
});
|
|
1209
1193
|
const walletName = walletIdentity.walletName;
|
|
1210
1194
|
const walletId = walletIdentity.walletId || undefined;
|
|
1211
|
-
if (selfHostedAction === "import") {
|
|
1212
|
-
const
|
|
1213
|
-
const hosting = hostProfile === "hosting";
|
|
1214
|
-
const signerBin = hosting ? "/opt/fased/signer/fased-signerd" : resolveSignerdBinaryPath();
|
|
1215
|
-
const controlSocket = hosting ? "/run/fased-signerd/control.sock" : resolveLocalSignerControlSocketPath(process.env);
|
|
1216
|
-
const signerImportCommand = [
|
|
1217
|
-
shellQuote(signerBin),
|
|
1218
|
-
"admin wallet import",
|
|
1219
|
-
`--control-socket ${shellQuote(controlSocket)}`,
|
|
1220
|
-
`--wallet-id ${shellQuote(effectiveWalletId)}`,
|
|
1221
|
-
`--locked-role ${shellQuote(walletPurpose)}`,
|
|
1222
|
-
`< ${shellQuote("/absolute/path/to/solana-keypair.json")}`
|
|
1223
|
-
].join(" ");
|
|
1224
|
-
const command = hosting ? `/usr/sbin/runuser -u fased-signer -- /usr/bin/env HOME=/var/lib/fased-signerd ${signerImportCommand}` : signerImportCommand;
|
|
1195
|
+
if (selfHostedAction === "import" && hostProfile === "hosting") {
|
|
1196
|
+
const signerWalletId = (walletId ?? walletPurpose).trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
1225
1197
|
await prompter.note([
|
|
1226
|
-
"
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
"
|
|
1230
|
-
].join("\n"), "
|
|
1198
|
+
"Hosting keeps plaintext wallet keys outside the app/Gateway OS account.",
|
|
1199
|
+
"From the VPS provider root console, place the Solana keypair in /root/wallet.json with mode 600, then run:",
|
|
1200
|
+
`/usr/local/sbin/fased-signer-wallet-import --wallet-id ${shellQuote(signerWalletId)} --locked-role ${shellQuote(walletPurpose)} < /root/wallet.json`,
|
|
1201
|
+
"Return to the app account, rerun onboarding, and choose Create with the same role and wallet ID. The signer reuses only that exact existing deny-all wallet, then activates the one RPC and registers it."
|
|
1202
|
+
].join("\n"), "Signer-owned Hosting import");
|
|
1231
1203
|
addAnotherWallet = await prompter.confirm({
|
|
1232
1204
|
message: "Run another wallet setup action?",
|
|
1233
1205
|
initialValue: false
|
|
1234
1206
|
});
|
|
1235
1207
|
continue;
|
|
1236
1208
|
}
|
|
1209
|
+
const importFile = selfHostedAction === "import" ? (await prompter.text({
|
|
1210
|
+
message: "Absolute path to owner-only Solana keypair JSON",
|
|
1211
|
+
validate: (value) => value.trim().startsWith("/") ? undefined : "Enter an absolute path and run chmod 600 on the file first"
|
|
1212
|
+
})).trim() : undefined;
|
|
1237
1213
|
const rpcKey = rpcEnvKeyFor(chain, walletId);
|
|
1238
1214
|
const currentRpcValue = (nextConfig.env?.vars?.[rpcKey] ?? "").trim() || String(process.env[rpcKey] ?? "").trim();
|
|
1239
1215
|
const rpcUrlInput = (await prompter.text({
|
|
@@ -1245,8 +1221,6 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1245
1221
|
if (!effectiveRpcUrl) {
|
|
1246
1222
|
throw new Error(`${chain.toUpperCase()} RPC URL is required for wallets.`);
|
|
1247
1223
|
}
|
|
1248
|
-
nextConfig = setConfigEnvVar(nextConfig, rpcKey, effectiveRpcUrl);
|
|
1249
|
-
process.env[rpcKey] = effectiveRpcUrl;
|
|
1250
1224
|
try {
|
|
1251
1225
|
if (mode === "local-signer-create") {
|
|
1252
1226
|
try {
|
|
@@ -1256,6 +1230,7 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1256
1230
|
walletId,
|
|
1257
1231
|
walletName,
|
|
1258
1232
|
rpcUrl: effectiveRpcUrl,
|
|
1233
|
+
role: walletPurpose,
|
|
1259
1234
|
force: true,
|
|
1260
1235
|
noDoctor: true,
|
|
1261
1236
|
noSignerHints: true,
|
|
@@ -1277,6 +1252,7 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1277
1252
|
walletId,
|
|
1278
1253
|
walletName,
|
|
1279
1254
|
rpcUrl: effectiveRpcUrl,
|
|
1255
|
+
role: walletPurpose,
|
|
1280
1256
|
force: true,
|
|
1281
1257
|
noDoctor: true,
|
|
1282
1258
|
noSignerHints: true,
|
|
@@ -1286,17 +1262,22 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1286
1262
|
throw err;
|
|
1287
1263
|
}
|
|
1288
1264
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1265
|
+
} else {
|
|
1266
|
+
await walletSetupCommand(runtime, {
|
|
1267
|
+
mode,
|
|
1268
|
+
chain,
|
|
1269
|
+
walletId,
|
|
1270
|
+
walletName,
|
|
1271
|
+
role: walletPurpose,
|
|
1272
|
+
rpcUrl: effectiveRpcUrl,
|
|
1273
|
+
importFile,
|
|
1274
|
+
noDoctor: true,
|
|
1275
|
+
noSignerHints: true,
|
|
1276
|
+
nonInteractive: true
|
|
1277
|
+
});
|
|
1299
1278
|
}
|
|
1279
|
+
nextConfig = setConfigEnvVar(nextConfig, rpcKey, effectiveRpcUrl);
|
|
1280
|
+
process.env[rpcKey] = effectiveRpcUrl;
|
|
1300
1281
|
walletCeremonyEvents.push({
|
|
1301
1282
|
mode,
|
|
1302
1283
|
chain,
|
|
@@ -1307,6 +1288,25 @@ async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
|
|
|
1307
1288
|
ok: true
|
|
1308
1289
|
});
|
|
1309
1290
|
createdOrImportedSelfHostedWalletThisRun = true;
|
|
1291
|
+
if (hostProfile !== "hosting") {
|
|
1292
|
+
const exportRecovery = await prompter.confirm({
|
|
1293
|
+
message: "Create an encrypted recovery package now?",
|
|
1294
|
+
initialValue: true
|
|
1295
|
+
});
|
|
1296
|
+
if (exportRecovery) {
|
|
1297
|
+
const defaultRecoveryPath = path.join(process.env.HOME || process.cwd(), `fased-${walletId ?? walletPurpose}-recovery.json`);
|
|
1298
|
+
const recoveryOutput = (await prompter.text({
|
|
1299
|
+
message: "New encrypted recovery package path",
|
|
1300
|
+
initialValue: defaultRecoveryPath,
|
|
1301
|
+
validate: (value) => path.isAbsolute(value.trim()) ? undefined : "Enter an absolute path for a new file"
|
|
1302
|
+
})).trim();
|
|
1303
|
+
await walletRecoveryExportCommand(runtime, {
|
|
1304
|
+
walletId: walletId ?? walletPurpose,
|
|
1305
|
+
output: recoveryOutput
|
|
1306
|
+
});
|
|
1307
|
+
await prompter.note([`Encrypted recovery package: ${recoveryOutput}`, "Keep the recovery password separately. The file contains ciphertext, wallet id, role, public address, and format metadata; it never contains plaintext key material."].join("\n"), "Wallet recovery");
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
1310
|
const agentDefaultBefore = readAgentDefaultWallet();
|
|
1311
1311
|
const existingWallet = readWalletProviderRegistry(process.env).wallets.find((entry) => entry.id === walletId);
|
|
1312
1312
|
upsertNamedWallet({
|