ethagent 3.3.4 → 4.0.0
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/.claude-plugin/marketplace.json +11 -0
- package/.claude-plugin/plugin.json +35 -0
- package/LICENSE +1 -1
- package/README.md +64 -104
- package/commands/ethagent.md +40 -0
- package/package.json +16 -16
- package/src/app/keybindings/KeybindingProvider.tsx +1 -6
- package/src/app/keybindings/types.ts +1 -6
- package/src/cli/ResetConfirmView.tsx +54 -53
- package/src/cli/demo.ts +86 -0
- package/src/cli/hookIo.ts +45 -0
- package/src/cli/main.tsx +94 -123
- package/src/cli/memoryGuard.ts +49 -0
- package/src/cli/reset.ts +28 -70
- package/src/cli/sessionStart.ts +33 -0
- package/src/cli/status.ts +46 -0
- package/src/cli/sync.ts +167 -0
- package/src/cli/syncAdapters/claude-code.ts +86 -0
- package/src/cli/syncAdapters/codex.ts +66 -0
- package/src/cli/syncAdapters/index.ts +45 -0
- package/src/cli/syncAdapters/managedBlock.ts +175 -0
- package/src/cli/syncAdapters/shared.ts +63 -0
- package/src/identity/continuity/envelopeParse.ts +20 -1
- package/src/identity/continuity/publicSkills.ts +3 -1
- package/src/identity/continuity/skills/publicSkillsSync.ts +2 -1
- package/src/identity/continuity/skills/scaffold.ts +5 -2
- package/src/identity/continuity/snapshots.ts +12 -5
- package/src/identity/continuity/storage/defaults.ts +20 -19
- package/src/identity/continuity/storage/status.ts +1 -1
- package/src/identity/ens/ensLookup/constants.ts +1 -1
- package/src/identity/manager/IdentityManager.tsx +33 -0
- package/src/identity/{hub → manager}/OperationalRoutes.tsx +37 -18
- package/src/identity/{hub → manager}/Routes.tsx +48 -34
- package/src/identity/{hub → manager}/continuity/ContinuityDashboardScreen.tsx +9 -19
- package/src/identity/{hub → manager}/continuity/RebackupStorageScreen.tsx +3 -3
- package/src/identity/manager/continuity/RecoveryConfirmScreen.tsx +102 -0
- package/src/identity/{hub → manager}/continuity/SavePromptScreen.tsx +2 -3
- package/src/identity/{hub → manager}/continuity/completion.ts +1 -1
- package/src/identity/{hub → manager}/continuity/effects.ts +1 -1
- package/src/identity/{hub → manager}/continuity/skills/DeleteSkillConfirmScreen.tsx +2 -2
- package/src/identity/{hub → manager}/continuity/skills/NewSkillScreen.tsx +0 -5
- package/src/identity/{hub → manager}/continuity/skills/NewSkillVisibilityScreen.tsx +4 -4
- package/src/identity/{hub → manager}/continuity/skills/SkillActionsScreen.tsx +6 -22
- package/src/identity/{hub → manager}/continuity/skills/SkillsTreeScreen.tsx +5 -17
- package/src/identity/{hub → manager}/continuity/snapshot.ts +1 -1
- package/src/identity/{hub → manager}/continuity/vault.ts +1 -1
- package/src/identity/{hub → manager}/create/CreateFlow.tsx +59 -32
- package/src/identity/{hub → manager}/create/effects.ts +19 -10
- package/src/identity/manager/create/importScan.ts +122 -0
- package/src/identity/{hub → manager}/custody/CustodyEditFlow.tsx +17 -61
- package/src/identity/{hub → manager}/custody/actions.ts +1 -15
- package/src/identity/{hub → manager}/custody/routes.tsx +20 -40
- package/src/identity/{hub → manager}/custody/transactions.ts +1 -0
- package/src/identity/{hub → manager}/custody/types.ts +1 -2
- package/src/identity/{hub → manager}/custody/useCustodyEffects.ts +1 -1
- package/src/identity/{hub → manager}/ens/EnsEditAdvancedScreens.tsx +2 -2
- package/src/identity/{hub → manager}/ens/EnsEditMaintenanceScreens.tsx +12 -23
- package/src/identity/{hub → manager}/ens/EnsEditReviewScreens.tsx +18 -42
- package/src/identity/{hub → manager}/ens/EnsEditRunners.tsx +1 -1
- package/src/identity/{hub → manager}/ens/EnsEditShared.tsx +0 -2
- package/src/identity/{hub → manager}/ens/EnsEditSimpleScreens.tsx +10 -19
- package/src/identity/{hub → manager}/ens/EnsFlow.tsx +133 -41
- package/src/identity/{hub → manager}/ens/EnsOperatorWalletsScreen.tsx +14 -19
- package/src/identity/{hub → manager}/ens/editCopy.ts +1 -14
- package/src/identity/{hub → manager}/profile/EditProfileFlow.tsx +99 -66
- package/src/identity/{hub → manager}/profile/effects.ts +1 -3
- package/src/identity/{hub → manager}/profile/operatorSave.ts +1 -1
- package/src/identity/{hub → manager}/profile/state.ts +1 -1
- package/src/identity/{hub/identityHubReducer.ts → manager/reducer.ts} +25 -26
- package/src/identity/{hub → manager}/restore/RestoreFlow.tsx +16 -24
- package/src/identity/{hub → manager}/restore/apply.ts +1 -1
- package/src/identity/{hub → manager}/restore/auth.ts +1 -1
- package/src/identity/{hub → manager}/restore/discover.ts +1 -1
- package/src/identity/{hub → manager}/restore/fetch.ts +1 -1
- package/src/identity/{hub → manager}/restore/restoreAdmin.ts +1 -1
- package/src/identity/{hub → manager}/restore/useRestoreEffects.ts +2 -9
- package/src/identity/{hub → manager}/settings/StorageCredentialScreen.tsx +10 -25
- package/src/identity/{hub → manager}/shared/components/DetailsScreen.tsx +5 -7
- package/src/identity/{hub → manager}/shared/components/ErrorScreen.tsx +6 -10
- package/src/identity/{hub → manager}/shared/components/FlowTimeline.tsx +4 -3
- package/src/identity/{hub → manager}/shared/components/IdentitySummary.tsx +19 -59
- package/src/identity/manager/shared/components/LazyMenu.tsx +147 -0
- package/src/identity/manager/shared/components/MenuScreen.tsx +220 -0
- package/src/identity/manager/shared/components/OperationCompleteScreen.tsx +28 -0
- package/src/identity/{hub → manager}/shared/components/UnlinkedIdentityScreen.tsx +9 -10
- package/src/identity/{hub → manager}/shared/components/WalletApprovalScreen.tsx +1 -2
- package/src/identity/manager/shared/components/Wordmark.tsx +54 -0
- package/src/identity/{hub → manager}/shared/components/menuFlagsFromReconciliation.ts +39 -15
- package/src/identity/{hub → manager}/shared/effects/profilePrep.ts +1 -1
- package/src/identity/manager/shared/effects/types.ts +30 -0
- package/src/identity/{hub → manager}/shared/model/copy.ts +0 -4
- package/src/identity/{hub → manager}/shared/model/errors.ts +32 -3
- package/src/identity/{hub → manager}/shared/model/network.ts +2 -2
- package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/hook.ts +5 -0
- package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/run.ts +1 -1
- package/src/identity/{hub/shared/reconciliation/useAgentReconciliation.ts → manager/shared/reconciliation/index.ts} +6 -0
- package/src/identity/{hub → manager}/shared/utils.ts +6 -10
- package/src/identity/{hub → manager}/transfer/TokenTransferFlow.tsx +3 -3
- package/src/identity/{hub → manager}/transfer/TokenTransferScreens.tsx +4 -10
- package/src/identity/{hub → manager}/transfer/effects.ts +1 -1
- package/src/identity/{hub → manager}/types.ts +5 -6
- package/src/identity/{hub/useIdentityHubContinuity.ts → manager/useContinuity.ts} +59 -27
- package/src/identity/{hub/useIdentityHubController.ts → manager/useController.ts} +38 -35
- package/src/identity/{hub/useIdentityHubSideEffects.ts → manager/useSideEffects.ts} +40 -4
- package/src/identity/registry/erc8004/discovery.ts +3 -17
- package/src/identity/registry/erc8004/utils.ts +1 -1
- package/src/identity/storage/ipfs.ts +21 -1
- package/src/identity/wallet/browserWallet/html.ts +10 -2
- package/src/identity/wallet/browserWallet/http.ts +18 -0
- package/src/identity/wallet/browserWallet/requestServer.ts +5 -1
- package/src/identity/wallet/browserWallet/requests.ts +10 -28
- package/src/identity/wallet/browserWallet/session.ts +26 -33
- package/src/identity/wallet/browserWallet/validation.ts +14 -0
- package/src/identity/wallet/browserWallet/walletPageSource.ts +22 -40
- package/src/identity/wallet/page/boot.ts +43 -0
- package/src/identity/wallet/page/config.ts +59 -0
- package/src/identity/wallet/page/constants.ts +12 -0
- package/src/identity/wallet/page/copy.ts +47 -68
- package/src/identity/wallet/page/css.ts +638 -0
- package/src/identity/wallet/page/{errorView.ts → errors.ts} +5 -14
- package/src/identity/wallet/page/{controller.ts → flow.ts} +4 -71
- package/src/identity/wallet/page/markup.ts +44 -34
- package/src/identity/wallet/page/{walletProvider.ts → provider.ts} +0 -3
- package/src/identity/wallet/page/resize.ts +95 -0
- package/src/identity/wallet/page/state.ts +135 -8
- package/src/identity/wallet/page/timeline.ts +161 -0
- package/src/identity/wallet/page/view.ts +22 -302
- package/src/storage/config.ts +30 -80
- package/src/storage/reset.ts +31 -0
- package/src/storage/secrets.ts +1 -16
- package/src/ui/Select.tsx +27 -5
- package/src/ui/Spinner.tsx +16 -15
- package/src/ui/Surface.tsx +21 -17
- package/src/ui/TextArea.tsx +173 -0
- package/src/ui/TextInput.tsx +31 -133
- package/src/ui/theme.ts +22 -13
- package/src/utils/clipboard.ts +0 -140
- package/src/app/FirstRun.tsx +0 -577
- package/src/app/FirstRunTimeline.tsx +0 -51
- package/src/app/firstRunConfig.ts +0 -26
- package/src/app/hooks/useCancelRequest.ts +0 -22
- package/src/app/hooks/useDoublePress.ts +0 -46
- package/src/app/hooks/useExitOnCtrlC.ts +0 -36
- package/src/auth/openaiOAuth/credentials.ts +0 -47
- package/src/auth/openaiOAuth/crypto.ts +0 -23
- package/src/auth/openaiOAuth/index.ts +0 -238
- package/src/auth/openaiOAuth/landingPage.ts +0 -116
- package/src/auth/openaiOAuth/listener.ts +0 -151
- package/src/auth/openaiOAuth/refresh.ts +0 -70
- package/src/auth/openaiOAuth/shared.ts +0 -115
- package/src/chat/ChatBottomPane.tsx +0 -296
- package/src/chat/ChatScreen.tsx +0 -1685
- package/src/chat/ConversationStack.tsx +0 -56
- package/src/chat/MessageList.tsx +0 -638
- package/src/chat/SessionStatus.tsx +0 -53
- package/src/chat/chatEnvironment.ts +0 -16
- package/src/chat/chatScreenUtils.ts +0 -194
- package/src/chat/chatSessionState.ts +0 -146
- package/src/chat/chatTurnContext.ts +0 -50
- package/src/chat/chatTurnOrchestrator.ts +0 -603
- package/src/chat/chatTurnRows.ts +0 -64
- package/src/chat/commands.ts +0 -494
- package/src/chat/continuityEditReview.ts +0 -42
- package/src/chat/display/DiffView.tsx +0 -193
- package/src/chat/display/SyntaxText.tsx +0 -192
- package/src/chat/display/toolCallDisplay.ts +0 -103
- package/src/chat/display/toolResultDisplay.ts +0 -19
- package/src/chat/input/ChatInput.tsx +0 -625
- package/src/chat/input/chatInputHelpers.ts +0 -62
- package/src/chat/input/chatInputState.ts +0 -247
- package/src/chat/input/chatPaste.ts +0 -49
- package/src/chat/input/imageRefs.ts +0 -30
- package/src/chat/input/inputRendering.tsx +0 -93
- package/src/chat/input/textCursor.ts +0 -212
- package/src/chat/messageMarkdown.ts +0 -220
- package/src/chat/messageRows.ts +0 -43
- package/src/chat/planImplementation.ts +0 -62
- package/src/chat/slashCommandHandlers.ts +0 -122
- package/src/chat/slashCommandViews.ts +0 -120
- package/src/chat/transcript/TranscriptView.tsx +0 -184
- package/src/chat/transcript/transcriptViewport.ts +0 -295
- package/src/chat/views/ContextLimitView.tsx +0 -95
- package/src/chat/views/ContinuityEditReviewView.tsx +0 -50
- package/src/chat/views/CopyPicker.tsx +0 -50
- package/src/chat/views/PermissionPrompt.tsx +0 -156
- package/src/chat/views/PermissionsView.tsx +0 -165
- package/src/chat/views/PlanApprovalView.tsx +0 -91
- package/src/chat/views/ResumeView.tsx +0 -273
- package/src/chat/views/RewindView.tsx +0 -412
- package/src/cli/preview.tsx +0 -14
- package/src/cli/updateNotice.ts +0 -54
- package/src/identity/continuity/privateEdit/apply.ts +0 -170
- package/src/identity/continuity/privateEdit/diff.ts +0 -6
- package/src/identity/continuity/privateEdit/files.ts +0 -23
- package/src/identity/continuity/privateEdit/types.ts +0 -28
- package/src/identity/continuity/privateEdit.ts +0 -46
- package/src/identity/hub/IdentityHub.tsx +0 -14
- package/src/identity/hub/continuity/RecoveryConfirmScreen.tsx +0 -104
- package/src/identity/hub/ens/effects.ts +0 -218
- package/src/identity/hub/shared/components/MenuScreen.tsx +0 -241
- package/src/identity/hub/shared/effects/types.ts +0 -53
- package/src/identity/hub/shared/reconciliation/index.ts +0 -14
- package/src/identity/wallet/page/grainient.ts +0 -278
- package/src/identity/wallet/page/html.ts +0 -28
- package/src/identity/wallet/page/styles/base.ts +0 -260
- package/src/identity/wallet/page/styles/components.ts +0 -262
- package/src/identity/wallet/page/styles/index.ts +0 -5
- package/src/identity/wallet/page/styles/responsive.ts +0 -247
- package/src/identity/wallet/page.tsx +0 -38
- package/src/mcp/approvals.ts +0 -113
- package/src/mcp/config.ts +0 -235
- package/src/mcp/manager.ts +0 -482
- package/src/mcp/managerHelpers.ts +0 -70
- package/src/mcp/names.ts +0 -19
- package/src/mcp/output.ts +0 -96
- package/src/models/ModelPicker.tsx +0 -1009
- package/src/models/catalog.ts +0 -327
- package/src/models/huggingface.ts +0 -712
- package/src/models/huggingfaceStorage.ts +0 -136
- package/src/models/llamacpp.ts +0 -848
- package/src/models/llamacppCommands.ts +0 -44
- package/src/models/llamacppConfig.ts +0 -34
- package/src/models/llamacppDiscovery.ts +0 -176
- package/src/models/llamacppOutput.ts +0 -65
- package/src/models/llamacppPreflight.ts +0 -158
- package/src/models/modelDisplay.ts +0 -180
- package/src/models/modelPickerCatalogFlow.ts +0 -56
- package/src/models/modelPickerCredentials.ts +0 -166
- package/src/models/modelPickerData.ts +0 -41
- package/src/models/modelPickerDisplay.tsx +0 -132
- package/src/models/modelPickerHfFlow.ts +0 -192
- package/src/models/modelPickerLocalRunnerFlow.ts +0 -115
- package/src/models/modelPickerOptions.ts +0 -457
- package/src/models/modelPickerTypes.ts +0 -69
- package/src/models/modelPickerUninstallFlow.ts +0 -48
- package/src/models/modelPickerViewHelpers.ts +0 -174
- package/src/models/modelRecommendation.ts +0 -139
- package/src/models/providerDisplay.ts +0 -16
- package/src/models/runtimeDetection.ts +0 -81
- package/src/models/uncensoredCatalog.ts +0 -86
- package/src/providers/anthropic.ts +0 -290
- package/src/providers/contracts.ts +0 -71
- package/src/providers/errors.ts +0 -80
- package/src/providers/gemini.ts +0 -391
- package/src/providers/openai-chat.ts +0 -474
- package/src/providers/openai-responses-format.ts +0 -177
- package/src/providers/openai-responses.ts +0 -306
- package/src/providers/openaiChatWire.ts +0 -124
- package/src/providers/registry.ts +0 -120
- package/src/providers/retry.ts +0 -58
- package/src/providers/sse.ts +0 -93
- package/src/runtime/compaction.ts +0 -395
- package/src/runtime/cwd.ts +0 -43
- package/src/runtime/providerTurn.ts +0 -38
- package/src/runtime/sessionMode.ts +0 -55
- package/src/runtime/systemPrompt.ts +0 -213
- package/src/runtime/textToolParser.ts +0 -161
- package/src/runtime/toolClaimGuards.ts +0 -143
- package/src/runtime/toolExecution.ts +0 -304
- package/src/runtime/toolIntent.ts +0 -143
- package/src/runtime/turn.ts +0 -369
- package/src/runtime/turnNudges.ts +0 -223
- package/src/runtime/turnTypes.ts +0 -86
- package/src/storage/factoryReset.ts +0 -127
- package/src/storage/history.ts +0 -58
- package/src/storage/permissions.ts +0 -76
- package/src/storage/rewind.ts +0 -266
- package/src/storage/sessionExport.ts +0 -49
- package/src/storage/sessions.ts +0 -495
- package/src/tools/bashSafety.ts +0 -186
- package/src/tools/bashTool.ts +0 -140
- package/src/tools/changeDirectoryTool.ts +0 -213
- package/src/tools/contracts.ts +0 -192
- package/src/tools/deleteFileTool.ts +0 -116
- package/src/tools/editTool.ts +0 -165
- package/src/tools/editUtils.ts +0 -170
- package/src/tools/fileDiff.ts +0 -261
- package/src/tools/listDirectoryTool.ts +0 -55
- package/src/tools/listSkillFilesTool.ts +0 -77
- package/src/tools/listSkillsTool.ts +0 -68
- package/src/tools/mcpResourceTools.ts +0 -95
- package/src/tools/permissionRules.ts +0 -85
- package/src/tools/privateContinuityEditTool.ts +0 -187
- package/src/tools/privateContinuityReadTool.ts +0 -106
- package/src/tools/readSkillTool.ts +0 -107
- package/src/tools/readTool.ts +0 -85
- package/src/tools/registry.ts +0 -103
- package/src/tools/writeFileTool.ts +0 -167
- package/src/ui/BrandSplash.tsx +0 -133
- package/src/ui/terminalTitle.ts +0 -30
- package/src/utils/images.ts +0 -140
- package/src/utils/markdownSegments.ts +0 -51
- package/src/utils/messages.ts +0 -37
- package/src/utils/withRetry.ts +0 -324
- /package/src/identity/{hub → manager}/continuity/state.ts +0 -0
- /package/src/identity/{hub → manager}/custody/helpers.ts +0 -0
- /package/src/identity/{hub → manager}/custody/preflight.ts +0 -0
- /package/src/identity/{hub → manager}/custody/state.ts +0 -0
- /package/src/identity/{hub → manager}/custody/useCustodyFlow.tsx +0 -0
- /package/src/identity/{hub → manager}/ens/EnsEditFlow.tsx +0 -0
- /package/src/identity/{hub → manager}/ens/advancedEnsValidation.ts +0 -0
- /package/src/identity/{hub → manager}/ens/state.ts +0 -0
- /package/src/identity/{hub → manager}/ens/transactions.ts +0 -0
- /package/src/identity/{hub → manager}/ens/types.ts +0 -0
- /package/src/identity/{hub → manager}/profile/identity.ts +0 -0
- /package/src/identity/{hub → manager}/restore/envelopes.ts +0 -0
- /package/src/identity/{hub → manager}/restore/helpers.ts +0 -0
- /package/src/identity/{hub → manager}/restore/recovery.ts +0 -0
- /package/src/identity/{hub → manager}/restore/resolve.ts +0 -0
- /package/src/identity/{hub → manager}/shared/components/BusyScreen.tsx +0 -0
- /package/src/identity/{hub → manager}/shared/components/NetworkScreen.tsx +0 -0
- /package/src/identity/{hub → manager}/shared/components/PinataJwtInput.tsx +0 -0
- /package/src/identity/{hub → manager}/shared/effects/receipts.ts +0 -0
- /package/src/identity/{hub → manager}/shared/effects/sync.ts +0 -0
- /package/src/identity/{hub → manager}/shared/model/format.ts +0 -0
- /package/src/identity/{hub → manager}/shared/operatorWallets.ts +0 -0
- /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/ownership.ts +0 -0
- /package/src/identity/{hub → manager}/shared/reconciliation/agentReconciliation/types.ts +0 -0
- /package/src/identity/{hub → manager}/shared/reconciliation/walletSetup.ts +0 -0
- /package/src/identity/{hub → manager}/shared/txGuard.ts +0 -0
- /package/src/identity/{hub → manager}/transfer/progress.ts +0 -0
- /package/src/identity/{hub → manager}/transfer/state.ts +0 -0
|
@@ -26,3 +26,21 @@ export function respondJson(res: http.ServerResponse, status: number, body: Reco
|
|
|
26
26
|
})
|
|
27
27
|
res.end(JSON.stringify(body))
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
function isLoopbackHost(host: string | undefined): boolean {
|
|
31
|
+
if (!host) return true
|
|
32
|
+
const hostname = host.replace(/:\d+$/, '').replace(/^\[|\]$/g, '')
|
|
33
|
+
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isAllowedWalletOrigin(req: http.IncomingMessage): boolean {
|
|
37
|
+
const origin = req.headers.origin
|
|
38
|
+
if (origin && origin !== 'null') {
|
|
39
|
+
try {
|
|
40
|
+
if (!isLoopbackHost(new URL(origin).host)) return false
|
|
41
|
+
} catch {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return isLoopbackHost(req.headers.host)
|
|
46
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import http from 'node:http'
|
|
2
2
|
import { randomUUID } from 'node:crypto'
|
|
3
3
|
import { walletPage } from './html.js'
|
|
4
|
-
import { readJson, respondHtml, respondJson } from './http.js'
|
|
4
|
+
import { isAllowedWalletOrigin, readJson, respondHtml, respondJson } from './http.js'
|
|
5
5
|
import { BrowserWalletError, type ReadyHandler } from './types.js'
|
|
6
6
|
import {
|
|
7
7
|
assertSessionToken,
|
|
@@ -43,6 +43,10 @@ export function startBrowserWalletServer<T>(args: {
|
|
|
43
43
|
|
|
44
44
|
const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse): Promise<void> => {
|
|
45
45
|
const url = new URL(req.url ?? '/', 'http://127.0.0.1')
|
|
46
|
+
if (req.method === 'POST' && !isAllowedWalletOrigin(req)) {
|
|
47
|
+
respondJson(res, 403, { ok: false, error: 'forbidden origin' })
|
|
48
|
+
return
|
|
49
|
+
}
|
|
46
50
|
if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/ethagent')) {
|
|
47
51
|
respondHtml(res, walletPage(args.title, sessionToken, args.payload))
|
|
48
52
|
return
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { recoverAddressFromSignature } from '../../crypto/eth.js'
|
|
2
1
|
import { normalizeWalletPayloadPurpose } from '../walletPurposeCompat.js'
|
|
3
2
|
import { startBrowserWalletServer } from './requestServer.js'
|
|
4
3
|
import type {
|
|
@@ -12,10 +11,11 @@ import type {
|
|
|
12
11
|
TransactionRequest,
|
|
13
12
|
} from './types.js'
|
|
14
13
|
import {
|
|
15
|
-
|
|
14
|
+
assertExpectedAccount,
|
|
16
15
|
chainIdHex,
|
|
17
16
|
parseAccount,
|
|
18
17
|
parseHex,
|
|
18
|
+
verifyRecoveredAccount,
|
|
19
19
|
} from './validation.js'
|
|
20
20
|
|
|
21
21
|
export async function requestBrowserWalletAccount(args: AccountRequest = {}): Promise<BrowserWalletAccount> {
|
|
@@ -55,9 +55,7 @@ export async function requestBrowserWalletSignature(args: SignatureRequest): Pro
|
|
|
55
55
|
}),
|
|
56
56
|
prepare: body => {
|
|
57
57
|
const account = parseAccount(body.account)
|
|
58
|
-
|
|
59
|
-
throw accountMismatchError(account, args.expectedAccount, args.purpose)
|
|
60
|
-
}
|
|
58
|
+
assertExpectedAccount(account, args.expectedAccount, args.purpose)
|
|
61
59
|
const message = args.messageForAccount ? args.messageForAccount(account) : args.message!
|
|
62
60
|
return { message }
|
|
63
61
|
},
|
|
@@ -65,13 +63,8 @@ export async function requestBrowserWalletSignature(args: SignatureRequest): Pro
|
|
|
65
63
|
const account = parseAccount(body.account)
|
|
66
64
|
const message = typeof body.message === 'string' ? body.message : ''
|
|
67
65
|
const signature = parseHex(body.signature, 'wallet signature')
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
const recovered = recoverAddressFromSignature(message, signature)
|
|
72
|
-
if (recovered.toLowerCase() !== account.toLowerCase()) {
|
|
73
|
-
throw new Error('Wallet signature does not match connected account')
|
|
74
|
-
}
|
|
66
|
+
assertExpectedAccount(account, args.expectedAccount, args.purpose)
|
|
67
|
+
verifyRecoveredAccount(message, signature, account)
|
|
75
68
|
return { account, message, signature }
|
|
76
69
|
},
|
|
77
70
|
})
|
|
@@ -101,9 +94,7 @@ export async function sendBrowserWalletTransaction(args: TransactionRequest): Pr
|
|
|
101
94
|
}),
|
|
102
95
|
complete: body => {
|
|
103
96
|
const account = parseAccount(body.account)
|
|
104
|
-
|
|
105
|
-
throw accountMismatchError(account, args.expectedAccount, args.purpose)
|
|
106
|
-
}
|
|
97
|
+
assertExpectedAccount(account, args.expectedAccount, args.purpose)
|
|
107
98
|
return { account, txHash: parseHex(body.txHash, 'transaction hash') }
|
|
108
99
|
},
|
|
109
100
|
})
|
|
@@ -140,9 +131,7 @@ export async function requestBrowserWalletSignatureAndTransaction<TPrepared>(
|
|
|
140
131
|
}),
|
|
141
132
|
prepare: body => {
|
|
142
133
|
const account = parseAccount(body.account)
|
|
143
|
-
|
|
144
|
-
throw accountMismatchError(account, args.expectedAccount, args.purpose)
|
|
145
|
-
}
|
|
134
|
+
assertExpectedAccount(account, args.expectedAccount, args.purpose)
|
|
146
135
|
const message = args.messageForAccount ? args.messageForAccount(account) : args.message!
|
|
147
136
|
return { message }
|
|
148
137
|
},
|
|
@@ -150,13 +139,8 @@ export async function requestBrowserWalletSignatureAndTransaction<TPrepared>(
|
|
|
150
139
|
const account = parseAccount(body.account)
|
|
151
140
|
const message = typeof body.message === 'string' ? body.message : ''
|
|
152
141
|
const signature = parseHex(body.signature, 'wallet signature')
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
const recovered = recoverAddressFromSignature(message, signature)
|
|
157
|
-
if (recovered.toLowerCase() !== account.toLowerCase()) {
|
|
158
|
-
throw new Error('Wallet signature does not match connected account')
|
|
159
|
-
}
|
|
142
|
+
assertExpectedAccount(account, args.expectedAccount, args.purpose)
|
|
143
|
+
verifyRecoveredAccount(message, signature, account)
|
|
160
144
|
const next = await args.prepareTransaction({ account, message, signature })
|
|
161
145
|
prepared = {
|
|
162
146
|
account,
|
|
@@ -176,9 +160,7 @@ export async function requestBrowserWalletSignatureAndTransaction<TPrepared>(
|
|
|
176
160
|
complete: body => {
|
|
177
161
|
if (!prepared) throw new Error('Wallet transaction was not prepared')
|
|
178
162
|
const account = parseAccount(body.account)
|
|
179
|
-
|
|
180
|
-
throw accountMismatchError(account, prepared.account, args.purpose)
|
|
181
|
-
}
|
|
163
|
+
assertExpectedAccount(account, prepared.account, args.purpose)
|
|
182
164
|
return {
|
|
183
165
|
account,
|
|
184
166
|
message: prepared.message,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import http from 'node:http'
|
|
2
2
|
import { randomUUID } from 'node:crypto'
|
|
3
|
-
import { recoverAddressFromSignature } from '../../crypto/eth.js'
|
|
4
3
|
import { normalizeWalletPayloadPurpose } from '../walletPurposeCompat.js'
|
|
5
4
|
import { walletPage } from './html.js'
|
|
6
|
-
import { readJson, respondHtml, respondJson } from './http.js'
|
|
5
|
+
import { isAllowedWalletOrigin, readJson, respondHtml, respondJson } from './http.js'
|
|
6
|
+
|
|
7
|
+
const SSE_DRAIN_MS = 250
|
|
7
8
|
import {
|
|
8
9
|
BrowserWalletError,
|
|
9
10
|
type BrowserWalletSession,
|
|
@@ -15,11 +16,12 @@ import {
|
|
|
15
16
|
type SignAndTransactionRequest,
|
|
16
17
|
} from './types.js'
|
|
17
18
|
import {
|
|
18
|
-
|
|
19
|
+
assertExpectedAccount,
|
|
19
20
|
chainIdHex,
|
|
20
21
|
parseAccount,
|
|
21
22
|
parseBrowserWalletErrorBody,
|
|
22
23
|
parseHex,
|
|
24
|
+
verifyRecoveredAccount,
|
|
23
25
|
} from './validation.js'
|
|
24
26
|
|
|
25
27
|
export async function openBrowserWalletSession(args: {
|
|
@@ -47,6 +49,10 @@ export async function openBrowserWalletSession(args: {
|
|
|
47
49
|
|
|
48
50
|
const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse): Promise<void> => {
|
|
49
51
|
const url = new URL(req.url ?? '/', 'http://127.0.0.1')
|
|
52
|
+
if ((req.method === 'POST' || url.pathname === '/events') && !isAllowedWalletOrigin(req)) {
|
|
53
|
+
respondJson(res, 403, { ok: false, error: 'forbidden origin' })
|
|
54
|
+
return
|
|
55
|
+
}
|
|
50
56
|
if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/ethagent')) {
|
|
51
57
|
respondHtml(res, walletPage(title, '', { kind: 'session-wait' }))
|
|
52
58
|
return
|
|
@@ -98,10 +104,15 @@ export async function openBrowserWalletSession(args: {
|
|
|
98
104
|
return
|
|
99
105
|
}
|
|
100
106
|
const finished = pending
|
|
107
|
+
try {
|
|
108
|
+
finished.resolve(body)
|
|
109
|
+
} catch (err) {
|
|
110
|
+
respondJson(res, 400, { ok: false, error: (err as Error).message })
|
|
111
|
+
return
|
|
112
|
+
}
|
|
101
113
|
pending = null
|
|
102
|
-
respondJson(res, 200, { ok: true })
|
|
103
114
|
clearTimeout(finished.timeout)
|
|
104
|
-
|
|
115
|
+
respondJson(res, 200, { ok: true })
|
|
105
116
|
return
|
|
106
117
|
}
|
|
107
118
|
if (req.method === 'POST' && url.pathname === '/cancel') {
|
|
@@ -167,7 +178,7 @@ export async function openBrowserWalletSession(args: {
|
|
|
167
178
|
...(opts.prepare ? { prepare: opts.prepare } : {}),
|
|
168
179
|
...(opts.prepareTransaction ? { prepareTransaction: opts.prepareTransaction } : {}),
|
|
169
180
|
resolve: body => {
|
|
170
|
-
|
|
181
|
+
resolve(opts.complete(body))
|
|
171
182
|
},
|
|
172
183
|
reject,
|
|
173
184
|
timeout,
|
|
@@ -194,9 +205,7 @@ export async function openBrowserWalletSession(args: {
|
|
|
194
205
|
...(req.timeoutMs !== undefined ? { timeoutMs: req.timeoutMs } : {}),
|
|
195
206
|
prepare: body => {
|
|
196
207
|
const account = parseAccount(body.account)
|
|
197
|
-
|
|
198
|
-
throw accountMismatchError(account, req.expectedAccount, req.purpose)
|
|
199
|
-
}
|
|
208
|
+
assertExpectedAccount(account, req.expectedAccount, req.purpose)
|
|
200
209
|
const message = req.messageForAccount ? req.messageForAccount(account) : req.message!
|
|
201
210
|
return { message }
|
|
202
211
|
},
|
|
@@ -204,13 +213,8 @@ export async function openBrowserWalletSession(args: {
|
|
|
204
213
|
const account = parseAccount(body.account)
|
|
205
214
|
const message = typeof body.message === 'string' ? body.message : ''
|
|
206
215
|
const signature = parseHex(body.signature, 'wallet signature')
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
const recovered = recoverAddressFromSignature(message, signature)
|
|
211
|
-
if (recovered.toLowerCase() !== account.toLowerCase()) {
|
|
212
|
-
throw new Error('Wallet signature does not match connected account')
|
|
213
|
-
}
|
|
216
|
+
assertExpectedAccount(account, req.expectedAccount, req.purpose)
|
|
217
|
+
verifyRecoveredAccount(message, signature, account)
|
|
214
218
|
return { account, message, signature }
|
|
215
219
|
},
|
|
216
220
|
})
|
|
@@ -229,9 +233,7 @@ export async function openBrowserWalletSession(args: {
|
|
|
229
233
|
...(req.timeoutMs !== undefined ? { timeoutMs: req.timeoutMs } : {}),
|
|
230
234
|
complete: body => {
|
|
231
235
|
const account = parseAccount(body.account)
|
|
232
|
-
|
|
233
|
-
throw accountMismatchError(account, req.expectedAccount, req.purpose)
|
|
234
|
-
}
|
|
236
|
+
assertExpectedAccount(account, req.expectedAccount, req.purpose)
|
|
235
237
|
return { account, txHash: parseHex(body.txHash, 'transaction hash') }
|
|
236
238
|
},
|
|
237
239
|
}),
|
|
@@ -262,9 +264,7 @@ export async function openBrowserWalletSession(args: {
|
|
|
262
264
|
...(req.timeoutMs !== undefined ? { timeoutMs: req.timeoutMs } : {}),
|
|
263
265
|
prepare: body => {
|
|
264
266
|
const account = parseAccount(body.account)
|
|
265
|
-
|
|
266
|
-
throw accountMismatchError(account, req.expectedAccount, req.purpose)
|
|
267
|
-
}
|
|
267
|
+
assertExpectedAccount(account, req.expectedAccount, req.purpose)
|
|
268
268
|
const message = req.messageForAccount ? req.messageForAccount(account) : req.message!
|
|
269
269
|
return { message }
|
|
270
270
|
},
|
|
@@ -272,13 +272,8 @@ export async function openBrowserWalletSession(args: {
|
|
|
272
272
|
const account = parseAccount(body.account)
|
|
273
273
|
const message = typeof body.message === 'string' ? body.message : ''
|
|
274
274
|
const signature = parseHex(body.signature, 'wallet signature')
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
const recovered = recoverAddressFromSignature(message, signature)
|
|
279
|
-
if (recovered.toLowerCase() !== account.toLowerCase()) {
|
|
280
|
-
throw new Error('Wallet signature does not match connected account')
|
|
281
|
-
}
|
|
275
|
+
assertExpectedAccount(account, req.expectedAccount, req.purpose)
|
|
276
|
+
verifyRecoveredAccount(message, signature, account)
|
|
282
277
|
const next = await req.prepareTransaction({ account, message, signature })
|
|
283
278
|
prepared = {
|
|
284
279
|
account,
|
|
@@ -296,9 +291,7 @@ export async function openBrowserWalletSession(args: {
|
|
|
296
291
|
complete: body => {
|
|
297
292
|
if (!prepared) throw new Error('Wallet transaction was not prepared')
|
|
298
293
|
const account = parseAccount(body.account)
|
|
299
|
-
|
|
300
|
-
throw accountMismatchError(account, prepared.account, req.purpose)
|
|
301
|
-
}
|
|
294
|
+
assertExpectedAccount(account, prepared.account, req.purpose)
|
|
302
295
|
return {
|
|
303
296
|
account,
|
|
304
297
|
message: prepared.message,
|
|
@@ -314,7 +307,7 @@ export async function openBrowserWalletSession(args: {
|
|
|
314
307
|
closed = true
|
|
315
308
|
if (pending) failPending(new Error('wallet session closed before request completed'))
|
|
316
309
|
pushEvent('done', {})
|
|
317
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
310
|
+
await new Promise(resolve => setTimeout(resolve, SSE_DRAIN_MS))
|
|
318
311
|
for (const res of sseClients) {
|
|
319
312
|
try { res.end() } catch { }
|
|
320
313
|
}
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import { getAddress, type Address, type Hex } from 'viem'
|
|
2
|
+
import { recoverAddressFromSignature } from '../../crypto/eth.js'
|
|
2
3
|
import { normalizeWalletPurposeValue } from '../walletPurposeCompat.js'
|
|
3
4
|
import type { BrowserWalletErrorPayload, WalletPurpose } from './types.js'
|
|
4
5
|
|
|
6
|
+
export function assertExpectedAccount(account: Address, expectedAccount: Address | undefined, purpose?: WalletPurpose): void {
|
|
7
|
+
if (expectedAccount && account.toLowerCase() !== expectedAccount.toLowerCase()) {
|
|
8
|
+
throw accountMismatchError(account, expectedAccount, purpose)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function verifyRecoveredAccount(message: string, signature: Hex, account: Address): void {
|
|
13
|
+
const recovered = recoverAddressFromSignature(message, signature)
|
|
14
|
+
if (recovered.toLowerCase() !== account.toLowerCase()) {
|
|
15
|
+
throw new Error('Wallet signature does not match connected account')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
5
19
|
export function parseBrowserWalletErrorBody(body: Record<string, unknown>): BrowserWalletErrorPayload {
|
|
6
20
|
const message = typeof body.message === 'string' && body.message.trim() ? body.message.trim() : 'Wallet request failed'
|
|
7
21
|
const code = typeof body.code === 'string' && body.code.trim() ? body.code.trim() : undefined
|
|
@@ -2,39 +2,28 @@ import { existsSync, readFileSync } from 'node:fs'
|
|
|
2
2
|
import { dirname, join } from 'node:path'
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const WALLET_PAGE_MODULE_FILES = [
|
|
7
|
-
join('page', 'types.ts'),
|
|
8
|
-
join('page', 'html.ts'),
|
|
9
|
-
join('page', 'constants.ts'),
|
|
10
|
-
join('page', 'styles', 'base.ts'),
|
|
11
|
-
join('page', 'styles', 'components.ts'),
|
|
12
|
-
join('page', 'styles', 'responsive.ts'),
|
|
13
|
-
join('page', 'styles', 'index.ts'),
|
|
14
|
-
join('page', 'markup.ts'),
|
|
15
|
-
join('page', 'grainient.ts'),
|
|
16
|
-
join('page', 'state.ts'),
|
|
17
|
-
join('page', 'copy.ts'),
|
|
18
|
-
join('page', 'errorView.ts'),
|
|
19
|
-
join('page', 'walletProvider.ts'),
|
|
20
|
-
join('page', 'view.ts'),
|
|
21
|
-
join('page', 'controller.ts'),
|
|
22
|
-
] as const
|
|
5
|
+
const WALLET_PAGE_DIR = 'page'
|
|
23
6
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
7
|
+
const WALLET_PAGE_PARTS = [
|
|
8
|
+
'types.ts',
|
|
9
|
+
'constants.ts',
|
|
10
|
+
'css.ts',
|
|
11
|
+
'markup.ts',
|
|
12
|
+
'config.ts',
|
|
13
|
+
'copy.ts',
|
|
14
|
+
'errors.ts',
|
|
15
|
+
'provider.ts',
|
|
16
|
+
'view.ts',
|
|
17
|
+
'resize.ts',
|
|
18
|
+
'timeline.ts',
|
|
19
|
+
'state.ts',
|
|
20
|
+
'flow.ts',
|
|
21
|
+
'boot.ts',
|
|
22
|
+
]
|
|
35
23
|
|
|
36
24
|
export function loadWalletPageRawSource(fromUrl = import.meta.url): string {
|
|
37
|
-
|
|
25
|
+
const dir = locateWalletPageSourceRoot(fromUrl)
|
|
26
|
+
return WALLET_PAGE_PARTS.map(part => readFileSync(join(dir, part), 'utf8')).join('\n')
|
|
38
27
|
}
|
|
39
28
|
|
|
40
29
|
export function loadWalletPageSource(fromUrl = import.meta.url): string {
|
|
@@ -61,25 +50,18 @@ export function stripWalletModuleSyntax(source: string): string {
|
|
|
61
50
|
|
|
62
51
|
function locateWalletPageSourceRoot(fromUrl: string): string {
|
|
63
52
|
for (const candidate of walletPageSourceRootCandidates(fromUrl)) {
|
|
64
|
-
if (
|
|
53
|
+
if (existsSync(join(candidate, WALLET_PAGE_PARTS[0]!))) return candidate
|
|
65
54
|
}
|
|
66
55
|
throw new Error('could not locate browser wallet page source files')
|
|
67
56
|
}
|
|
68
57
|
|
|
69
58
|
function walletPageSourceRootCandidates(fromUrl: string): string[] {
|
|
70
59
|
const start = dirname(fileURLToPath(fromUrl))
|
|
71
|
-
const candidates = [join(start, '..')]
|
|
60
|
+
const candidates = [join(start, '..', WALLET_PAGE_DIR)]
|
|
72
61
|
for (let dir = start; ; dir = dirname(dir)) {
|
|
73
|
-
candidates.push(join(dir, 'src', 'identity', 'wallet'))
|
|
62
|
+
candidates.push(join(dir, 'src', 'identity', 'wallet', WALLET_PAGE_DIR))
|
|
74
63
|
const parent = dirname(dir)
|
|
75
64
|
if (parent === dir) break
|
|
76
65
|
}
|
|
77
66
|
return Array.from(new Set(candidates))
|
|
78
67
|
}
|
|
79
|
-
|
|
80
|
-
function hasWalletPageSourceFiles(sourceRoot: string): boolean {
|
|
81
|
-
return [
|
|
82
|
-
...WALLET_PAGE_MODULE_FILES,
|
|
83
|
-
WALLET_PAGE_ENTRY_FILE,
|
|
84
|
-
].every(file => existsSync(join(sourceRoot, file)))
|
|
85
|
-
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
function attachWalletHandlers(): void {
|
|
2
|
+
if (handlersAttached) return
|
|
3
|
+
handlersAttached = true
|
|
4
|
+
approve.onclick = runWalletFlow
|
|
5
|
+
cancel.onclick = cancelFlow
|
|
6
|
+
window.addEventListener('keydown', (e) => {
|
|
7
|
+
if (e.key === 'Escape') {
|
|
8
|
+
if (!escapeAllowed()) { e.preventDefault(); return }
|
|
9
|
+
e.preventDefault()
|
|
10
|
+
cancelFlow()
|
|
11
|
+
} else if (e.key === 'Enter') {
|
|
12
|
+
if (!approve.hidden && !approve.disabled) { e.preventDefault(); runWalletFlow(); return }
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function bootWallet(): void {
|
|
18
|
+
initializeViewElements()
|
|
19
|
+
attachWalletHandlers()
|
|
20
|
+
applyFlowChrome()
|
|
21
|
+
setupCardResize()
|
|
22
|
+
if (!window.__WALLET_PREVIEW__) {
|
|
23
|
+
if (document.readyState === 'loading') {
|
|
24
|
+
document.addEventListener('DOMContentLoaded', bootWallet, { once: true })
|
|
25
|
+
} else {
|
|
26
|
+
if (config && config.kind === 'session-wait') {
|
|
27
|
+
startSessionMode()
|
|
28
|
+
} else {
|
|
29
|
+
runWalletFlow()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
window.__walletPreview = {
|
|
34
|
+
setState,
|
|
35
|
+
setConfig: (c: Partial<WalletConfig>) => { Object.assign(config, c); applyFlowChrome() },
|
|
36
|
+
}
|
|
37
|
+
runWalletFlow()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
injectStylesAndMarkup()
|
|
42
|
+
|
|
43
|
+
bootWallet()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const config: WalletConfig =
|
|
2
|
+
(window.__WALLET_CONFIG__ as WalletConfig) || {
|
|
3
|
+
sessionToken: 'preview',
|
|
4
|
+
kind: 'sign',
|
|
5
|
+
chainIdHex: '0xaa36a7',
|
|
6
|
+
message: 'identity proof for 0x9F2a???BC4e',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const CHAINS: Record<string, { name: string }> = {
|
|
10
|
+
"0x1": { name: "Ethereum Mainnet" },
|
|
11
|
+
"0xaa36a7": { name: "Sepolia" },
|
|
12
|
+
"0x2105": { name: "Base" },
|
|
13
|
+
"0x14a34": { name: "Base Sepolia" },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export interface FlowCopy {
|
|
17
|
+
accent: string;
|
|
18
|
+
tabTitle: string;
|
|
19
|
+
label: string;
|
|
20
|
+
title: string;
|
|
21
|
+
subtitle: string;
|
|
22
|
+
detail: string | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const FLOW_COPY: Record<string, FlowCopy> = {
|
|
26
|
+
account: { accent: "sign", tabTitle: "Connect Wallet", label: "Connection Request", title: "Connect Wallet", subtitle: "Shares your wallet address with the agent. No signature or transaction.", detail: null },
|
|
27
|
+
sign: { accent: "sign", tabTitle: "Sign Message", label: "Signature Request", title: "Sign Message", subtitle: "Signs a message to prove wallet ownership. No transaction.", detail: "message" },
|
|
28
|
+
"sign-transaction": { accent: "transaction", tabTitle: "Sign Snapshot", label: "Snapshot Signature", title: "Sign Snapshot", subtitle: "Signs your encrypted agent snapshot for restore access.", detail: null },
|
|
29
|
+
transaction: { accent: "transaction", tabTitle: "Submit Transaction", label: "Onchain Transaction", title: "Submit Transaction", subtitle: "Submits one onchain transaction from your wallet.", detail: "registry" },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const TRANSACTION_TITLES: Record<string, string> = {
|
|
33
|
+
"register-agent": "Mint Agent Token",
|
|
34
|
+
"create-agent": "Create Agent",
|
|
35
|
+
"update-ens-records": "Submit With ENS Controller Wallet",
|
|
36
|
+
"clear-ens-records": "Submit With ENS Controller Wallet",
|
|
37
|
+
"create-simple-ens-subdomain": "Submit With Connected Wallet",
|
|
38
|
+
"set-simple-ens-records": "Submit With Connected Wallet",
|
|
39
|
+
"create-agent-ens-subdomain": "Owner Wallet Required",
|
|
40
|
+
"set-agent-ens-records": "Owner Wallet Required",
|
|
41
|
+
"publish-transfer-snapshot": "Sender Wallet: Publish Snapshot",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export function transactionPurposeTitle(): string {
|
|
45
|
+
const key = config.purpose || "";
|
|
46
|
+
const fromPurpose = PURPOSE_COPY[key]?.flowTitle;
|
|
47
|
+
const explicit = TRANSACTION_TITLES[key];
|
|
48
|
+
return fromPurpose || explicit || FLOW_COPY.transaction!.title;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const STATE_TITLES = {
|
|
52
|
+
connecting: "Connecting Wallet",
|
|
53
|
+
approveSign: "Sign Message",
|
|
54
|
+
preparingTransaction: "Preparing Transaction",
|
|
55
|
+
approveTransaction: "Review Transaction",
|
|
56
|
+
error: "Wallet Error",
|
|
57
|
+
cancelled: "Cancelled",
|
|
58
|
+
default: "Wallet Action",
|
|
59
|
+
};
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
export const glyphs = {
|
|
2
|
+
ellipsis: "…",
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export function escapeHtml(value: unknown): string {
|
|
6
|
+
return String(value == null ? "" : value)
|
|
7
|
+
.replaceAll("&", "&")
|
|
8
|
+
.replaceAll("<", "<")
|
|
9
|
+
.replaceAll(">", ">")
|
|
10
|
+
.replaceAll("\"", """);
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
export const CLOSE_DELAY_MS = 10000
|
|
2
14
|
export const TX_CLOSE_DELAY_MS = 10000
|
|
3
15
|
export const CANCEL_CLOSE_DELAY_MS = 10000
|