ethagent 1.1.2 → 2.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.
Files changed (268) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +126 -30
  3. package/package.json +7 -2
  4. package/src/app/FirstRun.tsx +190 -146
  5. package/src/app/FirstRunTimeline.tsx +47 -0
  6. package/src/app/input/AppInputProvider.tsx +1 -1
  7. package/src/app/keybindings/KeybindingProvider.tsx +1 -1
  8. package/src/chat/ChatBottomPane.tsx +0 -1
  9. package/src/chat/ChatInput.tsx +6 -6
  10. package/src/chat/ChatScreen.tsx +35 -15
  11. package/src/chat/ContextLimitView.tsx +4 -4
  12. package/src/chat/ContinuityEditReviewView.tsx +10 -22
  13. package/src/chat/CopyPicker.tsx +0 -1
  14. package/src/chat/MessageList.tsx +62 -45
  15. package/src/chat/PermissionPrompt.tsx +13 -9
  16. package/src/chat/PlanApprovalView.tsx +3 -3
  17. package/src/chat/ResumeView.tsx +1 -4
  18. package/src/chat/RewindView.tsx +2 -2
  19. package/src/chat/chatInputState.ts +1 -1
  20. package/src/chat/chatScreenUtils.ts +22 -11
  21. package/src/chat/chatSessionState.ts +2 -2
  22. package/src/chat/chatTurnOrchestrator.ts +16 -81
  23. package/src/chat/commands.ts +1 -1
  24. package/src/chat/textCursor.ts +1 -1
  25. package/src/chat/transcriptViewport.ts +2 -7
  26. package/src/cli/ResetConfirmView.tsx +1 -1
  27. package/src/cli/main.tsx +9 -3
  28. package/src/cli/preview.tsx +0 -5
  29. package/src/cli/updateNotice.ts +4 -2
  30. package/src/identity/continuity/editor.ts +7 -107
  31. package/src/identity/continuity/envelope.ts +1048 -40
  32. package/src/identity/continuity/history.ts +4 -4
  33. package/src/identity/continuity/localBackup.ts +249 -0
  34. package/src/identity/continuity/privateEdit/apply.ts +170 -0
  35. package/src/identity/continuity/privateEdit/diff.ts +82 -0
  36. package/src/identity/continuity/privateEdit/files.ts +23 -0
  37. package/src/identity/continuity/privateEdit/types.ts +28 -0
  38. package/src/identity/continuity/privateEdit.ts +10 -298
  39. package/src/identity/continuity/publicSkills.ts +8 -9
  40. package/src/identity/continuity/snapshots.ts +17 -6
  41. package/src/identity/continuity/storage/defaults.ts +111 -0
  42. package/src/identity/continuity/storage/files.ts +72 -0
  43. package/src/identity/continuity/storage/markdown.ts +81 -0
  44. package/src/identity/continuity/storage/paths.ts +24 -0
  45. package/src/identity/continuity/storage/scaffold.ts +124 -0
  46. package/src/identity/continuity/storage/status.ts +86 -0
  47. package/src/identity/continuity/storage/types.ts +27 -0
  48. package/src/identity/continuity/storage.ts +32 -507
  49. package/src/identity/continuity/zipWriter.ts +95 -0
  50. package/src/identity/crypto/backupEnvelope.ts +14 -247
  51. package/src/identity/crypto/eth.ts +7 -7
  52. package/src/identity/ens/agentRecords.ts +96 -0
  53. package/src/identity/ens/ensAutomation/contracts.ts +38 -0
  54. package/src/identity/ens/ensAutomation/delete.ts +80 -0
  55. package/src/identity/ens/ensAutomation/names.ts +14 -0
  56. package/src/identity/ens/ensAutomation/operators.ts +29 -0
  57. package/src/identity/ens/ensAutomation/read.ts +114 -0
  58. package/src/identity/ens/ensAutomation/root.ts +63 -0
  59. package/src/identity/ens/ensAutomation/setup.ts +284 -0
  60. package/src/identity/ens/ensAutomation/transactions.ts +107 -0
  61. package/src/identity/ens/ensAutomation/types.ts +126 -0
  62. package/src/identity/ens/ensAutomation.ts +29 -0
  63. package/src/identity/ens/ensLookup/client.ts +43 -0
  64. package/src/identity/ens/ensLookup/constants.ts +26 -0
  65. package/src/identity/ens/ensLookup/discovery.ts +70 -0
  66. package/src/identity/ens/ensLookup/names.ts +34 -0
  67. package/src/identity/ens/ensLookup/records.ts +45 -0
  68. package/src/identity/ens/ensLookup/resolve.ts +75 -0
  69. package/src/identity/ens/ensLookup/tokenReference.ts +17 -0
  70. package/src/identity/ens/ensLookup/types.ts +38 -0
  71. package/src/identity/ens/ensLookup/validation.ts +72 -0
  72. package/src/identity/ens/ensLookup.ts +19 -0
  73. package/src/identity/ens/ensRegistration.ts +199 -0
  74. package/src/identity/ens/resolverDelegation.ts +48 -0
  75. package/src/identity/hub/IdentityHub.tsx +13 -817
  76. package/src/identity/hub/OperationalRoutes.tsx +370 -0
  77. package/src/identity/hub/Routes.tsx +361 -0
  78. package/src/identity/hub/advancedEnsValidation.ts +45 -0
  79. package/src/identity/hub/{screens → components}/DetailsScreen.tsx +14 -8
  80. package/src/identity/hub/{screens → components}/ErrorScreen.tsx +15 -5
  81. package/src/identity/hub/components/FlowTimeline.tsx +27 -0
  82. package/src/identity/hub/components/IdentitySummary.tsx +190 -0
  83. package/src/identity/hub/components/MenuScreen.tsx +237 -0
  84. package/src/identity/hub/{screens → components}/NetworkScreen.tsx +3 -3
  85. package/src/identity/hub/{screens/RebackupStorageScreen.tsx → components/PinataJwtInput.tsx} +21 -18
  86. package/src/identity/hub/components/UnlinkedIdentityScreen.tsx +76 -0
  87. package/src/identity/hub/{screens → components}/WalletApprovalScreen.tsx +9 -8
  88. package/src/identity/hub/components/menuFlagsFromReconciliation.ts +68 -0
  89. package/src/identity/hub/effects/create.ts +310 -0
  90. package/src/identity/hub/effects/ens/flows.ts +218 -0
  91. package/src/identity/hub/effects/ens/index.ts +11 -0
  92. package/src/identity/hub/effects/ens/transactions.ts +239 -0
  93. package/src/identity/hub/effects/index.ts +74 -0
  94. package/src/identity/hub/effects/profile/profileState.ts +173 -0
  95. package/src/identity/hub/effects/publicProfile/index.ts +5 -0
  96. package/src/identity/hub/effects/publicProfile/runPublicProfileSave.ts +646 -0
  97. package/src/identity/hub/effects/rebackup/index.ts +7 -0
  98. package/src/identity/hub/effects/rebackup/operatorVault.ts +378 -0
  99. package/src/identity/hub/effects/rebackup/runRebackup.ts +451 -0
  100. package/src/identity/hub/effects/receipts.ts +46 -0
  101. package/src/identity/hub/effects/restore/apply.ts +112 -0
  102. package/src/identity/hub/effects/restore/auth.ts +159 -0
  103. package/src/identity/hub/effects/restore/discover.ts +86 -0
  104. package/src/identity/hub/effects/restore/envelopes.ts +21 -0
  105. package/src/identity/hub/effects/restore/fetch.ts +25 -0
  106. package/src/identity/hub/effects/restore/index.ts +22 -0
  107. package/src/identity/hub/effects/restore/recovery.ts +135 -0
  108. package/src/identity/hub/effects/restore/resolve.ts +102 -0
  109. package/src/identity/hub/effects/restore/restoreEffects.ts +22 -0
  110. package/src/identity/hub/effects/restore/shared.ts +91 -0
  111. package/src/identity/hub/effects/restoreAdmin.ts +93 -0
  112. package/src/identity/hub/effects/shared/profilePrep.ts +139 -0
  113. package/src/identity/hub/effects/shared/snapshot.ts +336 -0
  114. package/src/identity/hub/effects/shared/sync.ts +190 -0
  115. package/src/identity/hub/effects/token-transfer/index.ts +6 -0
  116. package/src/identity/hub/effects/token-transfer/progress.ts +59 -0
  117. package/src/identity/hub/effects/token-transfer/runTokenTransfer.ts +299 -0
  118. package/src/identity/hub/effects/types.ts +53 -0
  119. package/src/identity/hub/effects/vault/preflight.ts +50 -0
  120. package/src/identity/hub/flows/continuity/ContinuityDashboardScreen.tsx +170 -0
  121. package/src/identity/hub/flows/continuity/RebackupStorageScreen.tsx +28 -0
  122. package/src/identity/hub/{screens → flows/continuity}/RecoveryConfirmScreen.tsx +28 -19
  123. package/src/identity/hub/flows/continuity/SavePromptScreen.tsx +49 -0
  124. package/src/identity/hub/{screens → flows/create}/CreateFlow.tsx +61 -62
  125. package/src/identity/hub/flows/custody/CustodyEditFlow.tsx +347 -0
  126. package/src/identity/hub/flows/custody/custodyEffects.ts +321 -0
  127. package/src/identity/hub/flows/custody/custodyFlowActions.ts +236 -0
  128. package/src/identity/hub/flows/custody/custodyFlowEffects.ts +163 -0
  129. package/src/identity/hub/flows/custody/custodyFlowHelpers.ts +25 -0
  130. package/src/identity/hub/flows/custody/custodyFlowRoutes.tsx +239 -0
  131. package/src/identity/hub/flows/custody/custodyFlowTypes.ts +45 -0
  132. package/src/identity/hub/flows/custody/useCustodyFlow.tsx +25 -0
  133. package/src/identity/hub/flows/ens/EnsEditAdvancedScreens.tsx +336 -0
  134. package/src/identity/hub/flows/ens/EnsEditFlow.tsx +397 -0
  135. package/src/identity/hub/flows/ens/EnsEditMaintenanceScreens.tsx +332 -0
  136. package/src/identity/hub/flows/ens/EnsEditReviewScreens.tsx +471 -0
  137. package/src/identity/hub/flows/ens/EnsEditRunners.tsx +198 -0
  138. package/src/identity/hub/flows/ens/EnsEditShared.tsx +162 -0
  139. package/src/identity/hub/flows/ens/EnsEditSimpleScreens.tsx +518 -0
  140. package/src/identity/hub/flows/ens/IdentityHubEnsFlow.tsx +299 -0
  141. package/src/identity/hub/flows/ens/OperatorWalletsScreen.tsx +398 -0
  142. package/src/identity/hub/flows/ens/ensEditCopy.ts +117 -0
  143. package/src/identity/hub/flows/ens/ensEditTypes.ts +91 -0
  144. package/src/identity/hub/flows/profile/EditProfileFlow.tsx +271 -0
  145. package/src/identity/hub/flows/restore/RestoreFlow.tsx +324 -0
  146. package/src/identity/hub/flows/restore/useRestoreFlowEffects.ts +77 -0
  147. package/src/identity/hub/{screens → flows/settings}/StorageCredentialScreen.tsx +23 -44
  148. package/src/identity/hub/flows/token-transfer/IdentityHubTokenTransferFlow.tsx +162 -0
  149. package/src/identity/hub/flows/token-transfer/TokenTransferScreens.tsx +256 -0
  150. package/src/identity/hub/identityHubReducer.ts +164 -99
  151. package/src/identity/hub/model/continuity.ts +94 -0
  152. package/src/identity/hub/model/copy.ts +35 -0
  153. package/src/identity/hub/model/custody.ts +54 -0
  154. package/src/identity/hub/model/ens.ts +49 -0
  155. package/src/identity/hub/model/errors.ts +140 -0
  156. package/src/identity/hub/model/format.ts +15 -0
  157. package/src/identity/hub/model/identity.ts +94 -0
  158. package/src/identity/hub/model/network.ts +32 -0
  159. package/src/identity/hub/model/transfer.ts +57 -0
  160. package/src/identity/hub/operatorWallets.ts +131 -0
  161. package/src/identity/hub/reconciliation/agentReconciliation/hook.ts +46 -0
  162. package/src/identity/hub/reconciliation/agentReconciliation/ownership.ts +129 -0
  163. package/src/identity/hub/reconciliation/agentReconciliation/run.ts +302 -0
  164. package/src/identity/hub/reconciliation/agentReconciliation/types.ts +17 -0
  165. package/src/identity/hub/reconciliation/index.ts +21 -0
  166. package/src/identity/hub/reconciliation/useAgentReconciliation.ts +10 -0
  167. package/src/identity/hub/reconciliation/walletSetup.ts +220 -0
  168. package/src/identity/hub/txGuard.ts +51 -0
  169. package/src/identity/hub/types.ts +17 -0
  170. package/src/identity/hub/useIdentityHubContinuity.ts +136 -0
  171. package/src/identity/hub/useIdentityHubController.ts +396 -0
  172. package/src/identity/hub/useIdentityHubSideEffects.ts +309 -0
  173. package/src/identity/hub/utils.ts +79 -0
  174. package/src/identity/identityCompat.ts +34 -0
  175. package/src/identity/profile/agentIcon.ts +61 -0
  176. package/src/identity/profile/imagePicker.ts +12 -12
  177. package/src/identity/registry/erc8004/abi.ts +14 -0
  178. package/src/identity/registry/erc8004/chains.ts +150 -0
  179. package/src/identity/registry/erc8004/client.ts +11 -0
  180. package/src/identity/registry/erc8004/discovery.ts +511 -0
  181. package/src/identity/registry/erc8004/metadata.ts +335 -0
  182. package/src/identity/registry/erc8004/ownership.ts +121 -0
  183. package/src/identity/registry/erc8004/preflight.ts +123 -0
  184. package/src/identity/registry/erc8004/transactions.ts +77 -0
  185. package/src/identity/registry/erc8004/types.ts +88 -0
  186. package/src/identity/registry/erc8004/uri.ts +59 -0
  187. package/src/identity/registry/erc8004/utils.ts +58 -0
  188. package/src/identity/registry/erc8004.ts +53 -1106
  189. package/src/identity/registry/fieldParsers.ts +28 -0
  190. package/src/identity/registry/operatorVault/bytecode.ts +98 -0
  191. package/src/identity/registry/operatorVault/constants.ts +38 -0
  192. package/src/identity/registry/operatorVault/read.ts +246 -0
  193. package/src/identity/registry/operatorVault/transactions.ts +81 -0
  194. package/src/identity/registry/operatorVault.ts +44 -0
  195. package/src/identity/storage/ipfs.ts +26 -24
  196. package/src/identity/wallet/browserWallet/gas.ts +41 -0
  197. package/src/identity/wallet/browserWallet/html.ts +106 -0
  198. package/src/identity/wallet/browserWallet/http.ts +28 -0
  199. package/src/identity/wallet/browserWallet/requestServer.ts +106 -0
  200. package/src/identity/wallet/browserWallet/requests.ts +191 -0
  201. package/src/identity/wallet/browserWallet/session.ts +325 -0
  202. package/src/identity/wallet/browserWallet/types.ts +192 -0
  203. package/src/identity/wallet/browserWallet/validation.ts +74 -0
  204. package/src/identity/wallet/browserWallet.ts +30 -393
  205. package/src/identity/wallet/page/constants.ts +5 -0
  206. package/src/identity/wallet/page/controller.ts +251 -0
  207. package/src/identity/wallet/page/copy.ts +340 -0
  208. package/src/identity/wallet/page/grainient.ts +278 -0
  209. package/src/identity/wallet/page/html.ts +28 -0
  210. package/src/identity/wallet/page/markup.ts +50 -0
  211. package/src/identity/wallet/page/state.ts +9 -0
  212. package/src/identity/wallet/page/styles/base.ts +259 -0
  213. package/src/identity/wallet/page/styles/components.ts +262 -0
  214. package/src/identity/wallet/page/styles/index.ts +5 -0
  215. package/src/identity/wallet/page/styles/responsive.ts +247 -0
  216. package/src/identity/wallet/page/types.ts +47 -0
  217. package/src/identity/wallet/page/view.ts +535 -0
  218. package/src/identity/wallet/page/walletProvider.ts +70 -0
  219. package/src/identity/wallet/page.tsx +38 -0
  220. package/src/identity/wallet/walletPurposeCompat.ts +27 -0
  221. package/src/mcp/manager.ts +0 -1
  222. package/src/models/ModelPicker.tsx +36 -30
  223. package/src/models/catalog.ts +5 -2
  224. package/src/models/huggingface.ts +9 -9
  225. package/src/models/llamacpp.ts +13 -13
  226. package/src/models/modelDisplay.ts +75 -0
  227. package/src/models/modelPickerOptions.ts +16 -3
  228. package/src/models/modelRecommendation.ts +0 -1
  229. package/src/providers/errors.ts +16 -0
  230. package/src/providers/gemini.ts +252 -39
  231. package/src/providers/registry.ts +2 -2
  232. package/src/providers/retry.ts +1 -1
  233. package/src/runtime/sessionMode.ts +1 -1
  234. package/src/runtime/systemPrompt.ts +2 -0
  235. package/src/runtime/toolExecution.ts +18 -22
  236. package/src/runtime/toolIntent.ts +0 -20
  237. package/src/runtime/turn.ts +0 -92
  238. package/src/storage/atomicWrite.ts +4 -1
  239. package/src/storage/config.ts +181 -5
  240. package/src/storage/identity.ts +9 -3
  241. package/src/storage/secrets.ts +2 -2
  242. package/src/tools/bashSafety.ts +8 -0
  243. package/src/tools/changeDirectoryTool.ts +1 -1
  244. package/src/tools/deleteFileTool.ts +4 -4
  245. package/src/tools/editTool.ts +4 -4
  246. package/src/tools/editUtils.ts +5 -5
  247. package/src/tools/privateContinuityEditTool.ts +4 -5
  248. package/src/tools/privateContinuityReadTool.ts +1 -2
  249. package/src/tools/registry.ts +30 -0
  250. package/src/tools/writeFileTool.ts +5 -5
  251. package/src/ui/BrandSplash.tsx +20 -85
  252. package/src/ui/ProgressBar.tsx +3 -5
  253. package/src/ui/Select.tsx +20 -8
  254. package/src/ui/Spinner.tsx +38 -3
  255. package/src/ui/Surface.tsx +2 -2
  256. package/src/ui/TextInput.tsx +63 -20
  257. package/src/ui/theme.ts +7 -34
  258. package/src/utils/openExternal.ts +21 -0
  259. package/src/utils/withRetry.ts +47 -3
  260. package/src/identity/hub/identityHubEffects.ts +0 -937
  261. package/src/identity/hub/identityHubModel.ts +0 -371
  262. package/src/identity/hub/screens/ContinuityDashboardScreen.tsx +0 -156
  263. package/src/identity/hub/screens/EditProfileFlow.tsx +0 -146
  264. package/src/identity/hub/screens/IdentitySummary.tsx +0 -106
  265. package/src/identity/hub/screens/MenuScreen.tsx +0 -117
  266. package/src/identity/hub/screens/RestoreFlow.tsx +0 -206
  267. package/src/identity/wallet/wallet-page/wallet.html +0 -1202
  268. /package/src/identity/hub/{screens → components}/BusyScreen.tsx +0 -0
@@ -0,0 +1,256 @@
1
+ import React from 'react'
2
+ import { Box, Text } from 'ink'
3
+ import { Surface } from '../../../../ui/Surface.js'
4
+ import { Select } from '../../../../ui/Select.js'
5
+ import { Spinner } from '../../../../ui/Spinner.js'
6
+ import { TextInput } from '../../../../ui/TextInput.js'
7
+ import { theme } from '../../../../ui/theme.js'
8
+ import { useAppInput } from '../../../../app/input/AppInputProvider.js'
9
+ import { openExternalUrl } from '../../../../utils/openExternal.js'
10
+ import type { EthagentIdentity } from '../../../../storage/config.js'
11
+ import type { BrowserWalletReady } from '../../../wallet/browserWallet.js'
12
+ import type { TokenTransferProgress } from '../../effects/types.js'
13
+ import { readCustodyMode } from '../../model/custody.js'
14
+ import { shortAddress, shortCid } from '../../model/format.js'
15
+ import { FlowTimeline } from '../../components/FlowTimeline.js'
16
+ import { OPEN_BROWSER_HINT } from '../../components/WalletApprovalScreen.js'
17
+
18
+ const TRANSFER_STEPS = ['Choose Receiver', 'Sender Signs', 'Receiver Signs', 'Sender Updates URI', 'Transfer Token']
19
+ const APPROVAL_GUARDRAIL = 'No approve(), setApprovalForAll(), transferFrom(), or token approval is requested.'
20
+
21
+ type TokenTransferTargetScreenProps = {
22
+ identity: EthagentIdentity
23
+ tokenNetworkLabel: string
24
+ error?: string
25
+ initialValue?: string
26
+ onSubmit: (value: string) => void
27
+ onBack: () => void
28
+ }
29
+
30
+ export const TokenTransferTargetScreen: React.FC<TokenTransferTargetScreenProps> = ({
31
+ identity,
32
+ tokenNetworkLabel,
33
+ error,
34
+ initialValue,
35
+ onSubmit,
36
+ onBack,
37
+ }) => {
38
+ const tokenValue = identity.agentId ? `#${identity.agentId}` : 'not created'
39
+ const senderValue = shortAddress(identity.ownerAddress ?? identity.address)
40
+ const custodyMode = readCustodyMode(identity.state)
41
+ return (
42
+ <Surface
43
+ title="Prepare Token Transfer"
44
+ subtitle={<FlowTimeline steps={TRANSFER_STEPS} current={1} />}
45
+ footer={<Text color={theme.dim}>Enter Next · Esc Back</Text>}
46
+ >
47
+ <Box flexDirection="column">
48
+ <StatusRow label="Token" value={tokenValue} />
49
+ <StatusRow label="Network" value={tokenNetworkLabel} />
50
+ <StatusRow label="Sender" value={senderValue} />
51
+ <Box marginTop={1} flexDirection="column">
52
+ <Text color={theme.textSubtle}>Use this before any ERC-8004 token transfer.</Text>
53
+ <Text color={theme.textSubtle}>Both signed wallets can read this snapshot; after transfer, restore with the receiver wallet.</Text>
54
+ <Text color={theme.textSubtle}>{APPROVAL_GUARDRAIL}</Text>
55
+ {custodyMode === 'advanced' ? (
56
+ <Text color={theme.textSubtle}>Advanced custody: connect the owner wallet ({senderValue}) to sign as sender.</Text>
57
+ ) : null}
58
+ </Box>
59
+ <Box marginTop={1} flexDirection="column">
60
+ <TextInput
61
+ label="Receiver Wallet"
62
+ initialValue={initialValue ?? ''}
63
+ placeholder="ENS name or 0x address"
64
+ validate={value => validateTargetInput(value)}
65
+ onSubmit={onSubmit}
66
+ onCancel={onBack}
67
+ />
68
+ </Box>
69
+ {error ? <Box marginTop={1}><Text color={theme.accentError}>{error}</Text></Box> : null}
70
+ </Box>
71
+ </Surface>
72
+ )
73
+ }
74
+
75
+ type TokenTransferSigningScreenProps = {
76
+ identity: EthagentIdentity
77
+ tokenNetworkLabel: string
78
+ targetHandle: string
79
+ targetAddress: string
80
+ progress: TokenTransferProgress | null
81
+ walletSession: BrowserWalletReady | null
82
+ onCancel: () => void
83
+ }
84
+
85
+ export const TokenTransferSigningScreen: React.FC<TokenTransferSigningScreenProps> = ({
86
+ identity,
87
+ tokenNetworkLabel,
88
+ targetHandle,
89
+ targetAddress,
90
+ progress,
91
+ walletSession,
92
+ onCancel,
93
+ }) => {
94
+ useAppInput((_input, key) => {
95
+ if (key.escape) onCancel()
96
+ if (key.return && walletSession?.url) {
97
+ openExternalUrl(walletSession.url)
98
+ }
99
+ }, { isActive: true })
100
+
101
+ const senderAddress = identity.ownerAddress ?? identity.address
102
+ const resolvedProgress = progress ?? {
103
+ phase: 'sender-sign' as const,
104
+ walletRole: 'sender' as const,
105
+ expectedAddress: senderAddress as TokenTransferProgress['expectedAddress'],
106
+ title: 'Use Sender Wallet',
107
+ detail: 'Sign to save a transfer snapshot.',
108
+ walletAction: 'Sign Snapshot',
109
+ label: 'preparing transfer snapshot...',
110
+ }
111
+ const phase = resolvedProgress.phase
112
+ const spinnerLabel = tokenTransferSpinnerLabel(resolvedProgress)
113
+ const activeRoleLabel = resolvedProgress.walletRole === 'receiver' ? 'Receiver' : 'Sender'
114
+ const otherWallet = resolvedProgress.walletRole === 'sender'
115
+ ? { label: 'Receiver', value: `${shortAddress(targetAddress)}${targetHandle !== targetAddress ? ` (${targetHandle})` : ''}` }
116
+ : { label: 'Sender', value: shortAddress(senderAddress) }
117
+ return (
118
+ <Surface
119
+ title="Prepare Token Transfer"
120
+ subtitle={<FlowTimeline steps={TRANSFER_STEPS} current={transferTimelineStep(phase)} />}
121
+ footer={<Text color={theme.dim}>Esc Back</Text>}
122
+ >
123
+ <Box flexDirection="column">
124
+ <StatusRow label="Token" value={identity.agentId ? `#${identity.agentId}` : 'not created'} />
125
+ <StatusRow label="Network" value={tokenNetworkLabel} />
126
+ <StatusRow label="Sender" value={shortAddress(senderAddress)} />
127
+ <StatusRow label="Receiver" value={`${shortAddress(targetAddress)}${targetHandle !== targetAddress ? ` (${targetHandle})` : ''}`} />
128
+ <Box marginTop={1} flexDirection="column">
129
+ <Text color={resolvedProgress.walletRole === 'none' ? theme.text : theme.accentPeriwinkle} bold={resolvedProgress.walletRole !== 'none'}>
130
+ {resolvedProgress.title}
131
+ </Text>
132
+ <Text color={theme.textSubtle}>{resolvedProgress.detail}</Text>
133
+ {resolvedProgress.expectedAddress ? (
134
+ <>
135
+ <StatusRow label={activeRoleLabel} value={shortAddress(resolvedProgress.expectedAddress)} emphasize />
136
+ <StatusRow label={otherWallet.label} value={otherWallet.value} />
137
+ </>
138
+ ) : null}
139
+ </Box>
140
+ {walletSession ? (
141
+ <Box marginTop={1} flexDirection="column">
142
+ <Text color={theme.accentPeriwinkle} underline>{walletSession.url}</Text>
143
+ <Text color={theme.dim}>{OPEN_BROWSER_HINT}</Text>
144
+ </Box>
145
+ ) : null}
146
+ <Box marginTop={1}>
147
+ <Spinner label={spinnerLabel} />
148
+ </Box>
149
+ </Box>
150
+ </Surface>
151
+ )
152
+ }
153
+
154
+ type TokenTransferReadyScreenProps = {
155
+ identity: EthagentIdentity
156
+ tokenNetworkLabel: string
157
+ targetHandle: string
158
+ targetAddress: string
159
+ snapshotCid: string
160
+ txHash: string
161
+ footer: React.ReactNode
162
+ backHint: string
163
+ onBack: () => void
164
+ }
165
+
166
+ export const TokenTransferReadyScreen: React.FC<TokenTransferReadyScreenProps> = ({
167
+ identity,
168
+ tokenNetworkLabel,
169
+ targetHandle,
170
+ targetAddress,
171
+ snapshotCid,
172
+ txHash,
173
+ footer,
174
+ backHint,
175
+ onBack,
176
+ }) => (
177
+ <Surface
178
+ title="Transfer Snapshot Ready"
179
+ subtitle={<FlowTimeline steps={TRANSFER_STEPS} current={5} />}
180
+ footer={footer}
181
+ >
182
+ <Box flexDirection="column">
183
+ <Text color={theme.text}>Snapshot published. Transfer the ERC-8004 token externally on {tokenNetworkLabel} from sender to receiver.</Text>
184
+ <Box marginTop={1} flexDirection="column">
185
+ <StatusRow label="Token" value={identity.agentId ? `#${identity.agentId}` : 'not created'} tone={identity.agentId ? 'ok' : 'warn'} />
186
+ <StatusRow label="Network" value={tokenNetworkLabel} tone="ok" />
187
+ <StatusRow label="Sender" value={shortAddress(identity.ownerAddress ?? identity.address)} tone="ok" />
188
+ <StatusRow label="Receiver" value={`${shortAddress(targetAddress)}${targetHandle !== targetAddress ? ` (${targetHandle})` : ''}`} tone="ok" />
189
+ <StatusRow label="Snapshot" value={shortCid(snapshotCid)} tone="ok" />
190
+ <StatusRow label="Token URI tx" value={shortHash(txHash)} tone="ok" />
191
+ </Box>
192
+ <Box marginTop={1} flexDirection="column">
193
+ <Text color={theme.textSubtle}>Use this process for every ERC-8004 token transfer.</Text>
194
+ <Text color={theme.textSubtle}>Both sender and receiver signatures can decrypt this snapshot.</Text>
195
+ <Text color={theme.textSubtle}>After transfer, use Load Agent with the receiver wallet.</Text>
196
+ <Text color={theme.textSubtle}>{APPROVAL_GUARDRAIL}</Text>
197
+ </Box>
198
+ <Box marginTop={1}>
199
+ <Select<'back'>
200
+ options={[
201
+ { value: 'back', role: 'section', label: 'Navigation' },
202
+ { value: 'back', label: 'Back', hint: backHint, role: 'utility' },
203
+ ]}
204
+ hintLayout="inline"
205
+ onSubmit={onBack}
206
+ onCancel={onBack}
207
+ />
208
+ </Box>
209
+ </Box>
210
+ </Surface>
211
+ )
212
+
213
+ type StatusRowProps = { label: string; value: string; tone?: 'ok' | 'warn'; emphasize?: boolean }
214
+ const StatusRow: React.FC<StatusRowProps> = ({ label, value, tone, emphasize }) => {
215
+ const color = emphasize ? theme.accentPeriwinkle : tone === 'ok' ? theme.text : tone === 'warn' ? theme.accentPeriwinkle : theme.text
216
+ return (
217
+ <Text>
218
+ <Text color={theme.textSubtle}>{label.padEnd(12)} </Text>
219
+ <Text color={color} bold={emphasize}>{value}</Text>
220
+ </Text>
221
+ )
222
+ }
223
+
224
+ function transferTimelineStep(phase: TokenTransferProgress['phase'] | undefined): number {
225
+ switch (phase) {
226
+ case 'sender-sign':
227
+ return 2
228
+ case 'target-sign':
229
+ return 3
230
+ case 'pinning':
231
+ case 'sender-transaction':
232
+ case 'confirming':
233
+ return 4
234
+ default:
235
+ return 2
236
+ }
237
+ }
238
+
239
+ function validateTargetInput(value: string): string | null {
240
+ const trimmed = value.trim()
241
+ if (!trimmed) return 'Enter the receiver wallet ENS name or 0x address'
242
+ if (trimmed.startsWith('0x') && !/^0x[0-9a-fA-F]{40}$/.test(trimmed)) return 'Enter a valid 0x address'
243
+ if (!trimmed.startsWith('0x') && !trimmed.includes('.')) return 'Enter an ENS name or 0x address'
244
+ return null
245
+ }
246
+
247
+ function shortHash(hash: string): string {
248
+ return hash.length > 14 ? `${hash.slice(0, 10)}...${hash.slice(-6)}` : hash
249
+ }
250
+
251
+ function tokenTransferSpinnerLabel(progress: TokenTransferProgress): string {
252
+ const label = progress.walletRole === 'none'
253
+ ? progress.title
254
+ : progress.walletAction ?? progress.title
255
+ return `${label.replace(/[.]+$/g, '')}...`
256
+ }
@@ -1,117 +1,114 @@
1
- import type { EthagentConfig, EthagentIdentity, SelectableNetwork } from '../../storage/config.js'
1
+ import type { EthagentIdentity, SelectableNetwork } from '../../storage/config.js'
2
2
  import type { Erc8004AgentCandidate, Erc8004RegistryConfig } from '../registry/erc8004.js'
3
+ import { networkForChainId } from '../registry/erc8004.js'
3
4
  import type { RegistryResolution } from '../registry/registryConfig.js'
4
5
  import type { AgentStateBackupEnvelope } from '../crypto/backupEnvelope.js'
5
6
  import type { ContinuitySnapshotEnvelope } from '../continuity/envelope.js'
6
- import type { IdentityHubErrorView } from './identityHubModel.js'
7
+ import type { AgentEnsRecordState, AgentEnsRecords } from '../ens/agentRecords.js'
8
+ import type { EnsSetupPlan } from '../ens/ensAutomation.js'
9
+ import type { WalletPurpose } from '../wallet/browserWallet.js'
10
+ import type { IdentityHubErrorView } from './model/errors.js'
11
+ import type { ApprovedOperatorWalletInput } from './operatorWallets.js'
12
+ import type { CustodyMode } from './model/custody.js'
7
13
 
8
14
  export type RestorePurpose = 'restore' | 'switch'
9
- export type DetailsView = Extract<Step, { kind: 'details' }>
10
- export type ProfileUpdates = { name?: string; description?: string; imagePath?: string }
11
- export type RestorableBackupEnvelope = AgentStateBackupEnvelope | ContinuitySnapshotEnvelope
15
+ type RestoreNotFoundReason = 'no-owner-or-operator' | 'search-incomplete' | 'cancelled'
16
+ export type ProfileUpdates = {
17
+ name?: string
18
+ description?: string
19
+ imagePath?: string
20
+ ensName?: string
21
+ custodyMode?: 'simple' | 'advanced'
22
+ ownerAddress?: string
23
+ approvedOperatorWallets?: ApprovedOperatorWalletInput[]
24
+ activeOperatorAddress?: string
25
+ operatorVaultAddress?: string
26
+ restoreAccessEpoch?: number
27
+ bumpRestoreAccessEpoch?: boolean
28
+ custodyPhase?: 'switch-advanced' | 'switch-simple'
29
+ }
30
+
31
+ type RestorableBackupEnvelope = AgentStateBackupEnvelope | ContinuitySnapshotEnvelope
12
32
 
13
33
  export type Step =
14
34
  | { kind: 'menu' }
15
35
  | { kind: 'replace-confirm'; next: 'create' | 'restore' }
16
- | { kind: 'create-name'; error?: string }
17
- | { kind: 'create-description'; name: string }
36
+ | { kind: 'create-name'; name?: string; error?: string }
37
+ | { kind: 'create-description'; name: string; description?: string }
18
38
  | { kind: 'create-network'; name: string; description: string }
19
- | { kind: 'create-preflight'; name: string; description: string; network?: SelectableNetwork }
20
- | { kind: 'create-registry'; name: string; description: string; resolution: RegistryResolution; error?: string }
21
- | { kind: 'create-signing'; name: string; description: string; registry: Erc8004RegistryConfig; pinataJwt?: string }
22
- | { kind: 'create-storage'; name: string; description: string; registry: Erc8004RegistryConfig; error?: string; pinataJwt?: string }
23
- | { kind: 'restore-owner'; purpose?: RestorePurpose }
39
+ | { kind: 'create-custody'; name: string; description: string; network?: SelectableNetwork }
40
+ | { kind: 'create-preflight'; name: string; description: string; network?: SelectableNetwork; custodyMode: CustodyMode }
41
+ | { kind: 'create-registry'; name: string; description: string; resolution: RegistryResolution; custodyMode: CustodyMode; error?: string }
42
+ | { kind: 'create-signing'; name: string; description: string; registry: Erc8004RegistryConfig; custodyMode: CustodyMode; pinataJwt?: string }
43
+ | { kind: 'create-storage'; name: string; description: string; registry: Erc8004RegistryConfig; custodyMode: CustodyMode; error?: string; pinataJwt?: string }
44
+ | { kind: 'first-run-ens-prompt'; identity: EthagentIdentity; registry: Erc8004RegistryConfig }
24
45
  | { kind: 'restore-wallet'; purpose?: RestorePurpose }
25
46
  | { kind: 'restore-network'; ownerHandle: string; purpose?: RestorePurpose }
26
47
  | { kind: 'restore-registry'; ownerHandle: string; error?: string; purpose?: RestorePurpose }
27
- | { kind: 'restore-discovering'; ownerHandle: string; registry: Erc8004RegistryConfig; purpose?: RestorePurpose }
28
- | { kind: 'restore-token-id'; ownerHandle: string; registry: Erc8004RegistryConfig; error?: string; purpose?: RestorePurpose }
29
- | { kind: 'restore-select-token'; ownerHandle: string; registry: Erc8004RegistryConfig; candidates: Erc8004AgentCandidate[]; purpose?: RestorePurpose }
30
- | { kind: 'restore-fetching'; cid: string; apiUrl: string; candidate: Erc8004AgentCandidate; purpose?: RestorePurpose }
31
- | { kind: 'restore-authorizing'; cid: string; apiUrl: string; envelope: RestorableBackupEnvelope; candidate: Erc8004AgentCandidate; purpose?: RestorePurpose }
32
- | { kind: 'rebackup-signing'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; pinataJwt?: string; profileUpdates?: ProfileUpdates; returnTo?: Step }
33
- | { kind: 'rebackup-storage'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; error?: string; pinataJwt?: string; profileUpdates?: ProfileUpdates; returnTo?: Step }
48
+ | { kind: 'restore-discovering'; ownerHandle: string; registry: Erc8004RegistryConfig; purpose?: RestorePurpose; abortSignal?: AbortSignal }
49
+ | { kind: 'restore-recovery-input'; ownerHandle: string; registry: Erc8004RegistryConfig; purpose?: RestorePurpose }
50
+ | { kind: 'restore-ens-input'; ownerHandle: string; registry: Erc8004RegistryConfig; purpose?: RestorePurpose; busy?: boolean; error?: string }
51
+ | { kind: 'restore-token-id-input'; ownerHandle: string; registry: Erc8004RegistryConfig; purpose?: RestorePurpose; busy?: boolean; error?: string }
52
+ | { kind: 'restore-not-found'; ownerHandle: string; registry: Erc8004RegistryConfig; requesterAddress?: string; reason: RestoreNotFoundReason; purpose?: RestorePurpose }
53
+ | { kind: 'restore-select-token'; ownerHandle: string; registry: Erc8004RegistryConfig; candidates: Erc8004AgentCandidate[]; requesterAddress?: string; purpose?: RestorePurpose }
54
+ | { kind: 'restore-fetching'; cid: string; apiUrl: string; candidate: Erc8004AgentCandidate; requesterAddress?: string; purpose?: RestorePurpose }
55
+ | { kind: 'restore-authorizing'; cid: string; apiUrl: string; envelope: RestorableBackupEnvelope; candidate: Erc8004AgentCandidate; requesterAddress?: string; purpose?: RestorePurpose }
56
+ | { kind: 'rebackup-signing'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; pinataJwt?: string; profileUpdates?: ProfileUpdates; returnTo?: Step; walletPurpose?: WalletPurpose; vaultAddress?: `0x${string}` }
57
+ | { kind: 'rebackup-storage'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; error?: string; pinataJwt?: string; profileUpdates?: ProfileUpdates; returnTo?: Step; walletPurpose?: WalletPurpose; vaultAddress?: `0x${string}` }
58
+ | { kind: 'public-profile-signing'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; pinataJwt?: string; profileUpdates?: ProfileUpdates; returnTo?: Step; vaultAddress?: `0x${string}` }
59
+ | { kind: 'public-profile-storage'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; error?: string; pinataJwt?: string; profileUpdates?: ProfileUpdates; returnTo?: Step; vaultAddress?: `0x${string}` }
34
60
  | { kind: 'continuity-private'; notice?: string; editorOpened?: boolean }
35
61
  | { kind: 'continuity-public'; notice?: string; editorOpened?: boolean }
36
62
  | { kind: 'rebackup-confirm'; back: Step }
37
63
  | { kind: 'recovery-refetch-confirm'; back: Step }
38
64
  | { kind: 'recovery-refetching'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; back: Step }
39
65
  | { kind: 'rebackup-start'; back: Step }
40
- | { kind: 'edit-profile-name'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; returnTo?: Step }
41
- | { kind: 'edit-profile-description'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; name: string; returnTo?: Step }
42
- | { kind: 'edit-profile-image'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; name: string; description: string; error?: string; returnTo?: Step }
66
+ | { kind: 'edit-profile-name'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; name?: string; description?: string; imagePath?: string; returnTo?: Step }
67
+ | { kind: 'edit-profile-description'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; name: string; description?: string; imagePath?: string; returnTo?: Step }
68
+ | { kind: 'edit-profile-image'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; name: string; description: string; imagePath?: string; error?: string; returnTo?: Step }
69
+ | { kind: 'edit-profile-review'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; name: string; description: string; imagePath?: string; returnTo?: Step }
70
+ | { kind: 'edit-profile-ens'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; returnTo?: Step; initialView?: 'advanced' }
71
+ | { kind: 'ens-records-tx'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; fullName: string; records: AgentEnsRecords; currentRecords?: AgentEnsRecordState; ownerAddress?: string; returnTo?: Step; clearRecords?: boolean }
72
+ | { kind: 'ens-setup-registry-tx'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; setup: EnsSetupPlan; returnTo?: Step }
73
+ | { kind: 'ens-setup-records-tx'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; setup: EnsSetupPlan; returnTo?: Step; registryTxHash?: string }
74
+ | { kind: 'ens-clear-flow-running'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; fullName: string; ownerAddress: `0x${string}`; records: AgentEnsRecords; currentRecords?: AgentEnsRecordState; pinataJwt?: string; returnTo?: Step }
75
+ | { kind: 'ens-update-flow-running'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; fullName: string; ownerAddress: `0x${string}`; records: AgentEnsRecords; currentRecords?: AgentEnsRecordState; pinataJwt?: string; returnTo?: Step }
76
+ | { kind: 'ens-link-flow-running'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; setup: EnsSetupPlan; pinataJwt?: string; returnTo?: Step }
77
+ | { kind: 'manage-ens-operators'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; returnTo?: Step; notice?: string; error?: string }
78
+ | { kind: 'custody-model'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; returnTo?: Step; notice?: string }
79
+ | { kind: 'custody-advanced-confirm'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; returnTo?: Step }
80
+ | { kind: 'custody-simple-confirm'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; returnTo?: Step }
81
+ | { kind: 'custody-vault-deploy-tx'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; profileUpdates: ProfileUpdates; returnTo?: Step }
82
+ | { kind: 'custody-vault-deposit-tx'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; vaultAddress: `0x${string}`; profileUpdates: ProfileUpdates; returnTo?: Step }
83
+ | { kind: 'custody-vault-unwrap-tx'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; vaultAddress: `0x${string}`; profileUpdates: ProfileUpdates; returnTo?: Step; agentIds?: string[] }
84
+ | { kind: 'custody-vault-withdraw-discovering'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; vaultAddress: `0x${string}`; returnTo?: Step; returnContext?: 'ens' | 'simple-exit' }
85
+ | { kind: 'custody-vault-withdraw-pick-token'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; vaultAddress: `0x${string}`; tokens: ReadonlyArray<{ agentId: string }>; returnTo?: Step; returnContext?: 'ens' | 'simple-exit' }
86
+ | { kind: 'custody-vault-withdraw-tx'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; vaultAddress: `0x${string}`; agentId?: string; returnTo?: Step; returnContext?: 'ens' | 'simple-exit' }
87
+ | { kind: 'custody-vault-withdraw-done'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; vaultAddress: `0x${string}`; recipient: `0x${string}`; returnTo?: Step; returnContext?: 'ens' | 'simple-exit' }
88
+ | { kind: 'custody-advanced-done'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; vaultAddress?: `0x${string}`; returnTo?: Step }
89
+ | { kind: 'custody-simple-done'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; returnTo?: Step }
90
+ | { kind: 'token-transfer-target'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; error?: string; previousTarget?: string; returnTo?: Step }
91
+ | { kind: 'token-transfer-resolving'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; targetHandle: string; returnTo?: Step }
92
+ | { kind: 'token-transfer-storage'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; targetHandle: string; targetAddress: string; error?: string; pinataJwt?: string; returnTo?: Step }
93
+ | { kind: 'token-transfer-signing'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; targetHandle: string; targetAddress: string; pinataJwt?: string; returnTo?: Step }
94
+ | { kind: 'token-transfer-ready'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; targetHandle: string; targetAddress: string; snapshotCid: string; txHash: string; returnTo?: Step }
43
95
  | { kind: 'storage-credential' }
44
96
  | { kind: 'storage-credential-input'; error?: string }
45
97
  | { kind: 'storage-credential-forget-confirm' }
46
98
  | { kind: 'details' }
99
+ | { kind: 'save-prompt'; back: Step }
47
100
  | { kind: 'busy'; label: string }
48
101
  | { kind: 'error'; error: IdentityHubErrorView; back: Step }
102
+ | { kind: 'identity-unlinked'; identity: EthagentIdentity; registry: Erc8004RegistryConfig; onChainOwner?: string; back: Step }
49
103
 
50
104
  export type Action =
51
- | { type: 'goMenu' }
52
- | { type: 'startCreate'; hasIdentity: boolean }
53
- | { type: 'confirmReplace' }
54
- | { type: 'cancelReplace' }
55
- | { type: 'nameSubmitted'; name: string }
56
- | { type: 'descriptionSubmitted'; name: string; description: string }
57
- | { type: 'preflightResolved'; step: Step }
58
- | { type: 'registrySubmitted'; step: Step }
59
- | { type: 'storageSubmitted'; step: Step }
60
- | { type: 'walletSigned'; step: Step }
61
- | { type: 'pinned'; step: Step }
62
- | { type: 'registered'; step: Step }
63
- | { type: 'startRestore' }
64
- | { type: 'ownerSubmitted'; step: Step }
65
- | { type: 'restoreRegistrySubmitted'; step: Step }
66
- | { type: 'discovered'; step: Step }
67
- | { type: 'tokenSelected'; step: Step }
68
- | { type: 'fetched'; step: Step }
69
- | { type: 'authorized' }
70
- | { type: 'openDetails' }
71
- | { type: 'openCopyPicker' }
72
- | { type: 'closeCopyPicker' }
73
- | { type: 'error'; error: IdentityHubErrorView; back: Step }
105
+ | { type: 'setStep'; step: Step }
74
106
  | { type: 'back'; from: Step }
75
107
 
76
108
  export function identityHubReducer(state: Step, action: Action): Step {
77
109
  switch (action.type) {
78
- case 'goMenu':
79
- return { kind: 'menu' }
80
- case 'startCreate':
81
- if (action.hasIdentity) return { kind: 'replace-confirm', next: 'create' }
82
- return { kind: 'create-name' }
83
- case 'confirmReplace':
84
- return { kind: 'create-name' }
85
- case 'cancelReplace':
86
- return { kind: 'menu' }
87
- case 'nameSubmitted':
88
- return { kind: 'create-description', name: action.name }
89
- case 'descriptionSubmitted':
90
- return { kind: 'create-network', name: action.name, description: action.description }
91
- case 'preflightResolved':
92
- case 'registrySubmitted':
93
- case 'storageSubmitted':
94
- case 'walletSigned':
95
- case 'pinned':
96
- case 'registered':
97
- case 'ownerSubmitted':
98
- case 'restoreRegistrySubmitted':
99
- case 'discovered':
100
- case 'tokenSelected':
101
- case 'fetched':
110
+ case 'setStep':
102
111
  return action.step
103
- case 'startRestore':
104
- return { kind: 'restore-wallet' }
105
- case 'openDetails':
106
- return { kind: 'details' }
107
- case 'openCopyPicker':
108
- if (state.kind === 'details') return { kind: 'details' }
109
- return state
110
- case 'closeCopyPicker':
111
- if (state.kind === 'details') return { kind: 'details' }
112
- return state
113
- case 'error':
114
- return { kind: 'error', error: action.error, back: action.back }
115
112
  case 'back':
116
113
  return backStep(action.from)
117
114
  default:
@@ -124,35 +121,46 @@ function backStep(from: Step): Step {
124
121
  case 'create-name':
125
122
  return { kind: 'menu' }
126
123
  case 'create-description':
127
- return { kind: 'create-name' }
124
+ return { kind: 'create-name', name: from.name }
128
125
  case 'create-network':
129
- return { kind: 'create-description', name: from.name }
130
- case 'create-preflight':
126
+ return { kind: 'create-description', name: from.name, description: from.description }
127
+ case 'create-custody':
131
128
  return { kind: 'create-network', name: from.name, description: from.description }
129
+ case 'create-preflight':
130
+ return { kind: 'create-custody', name: from.name, description: from.description, ...(from.network ? { network: from.network } : {}) }
132
131
  case 'create-registry':
133
- return { kind: 'create-network', name: from.name, description: from.description }
134
- case 'create-signing':
135
- return { kind: 'create-network', name: from.name, description: from.description }
136
- case 'create-storage':
137
- return { kind: 'create-network', name: from.name, description: from.description }
138
- case 'restore-owner':
132
+ return { kind: 'create-custody', name: from.name, description: from.description, ...(from.resolution.network ? { network: from.resolution.network } : {}) }
133
+ case 'create-signing': {
134
+ const sigNetwork = networkForChainId(from.registry.chainId)
135
+ return { kind: 'create-custody', name: from.name, description: from.description, ...(sigNetwork ? { network: sigNetwork } : {}) }
136
+ }
137
+ case 'create-storage': {
138
+ const stoNetwork = networkForChainId(from.registry.chainId)
139
+ return { kind: 'create-custody', name: from.name, description: from.description, ...(stoNetwork ? { network: stoNetwork } : {}) }
140
+ }
141
+ case 'first-run-ens-prompt':
139
142
  return { kind: 'menu' }
140
143
  case 'restore-wallet':
141
- return { kind: 'restore-owner', purpose: from.purpose }
142
144
  case 'restore-network':
143
- return { kind: 'restore-owner', purpose: from.purpose }
145
+ return { kind: 'menu' }
144
146
  case 'restore-registry':
145
147
  return { kind: 'restore-network', ownerHandle: from.ownerHandle, purpose: from.purpose }
146
148
  case 'restore-discovering':
147
149
  return { kind: 'restore-network', ownerHandle: from.ownerHandle, purpose: from.purpose }
148
- case 'restore-token-id':
150
+ case 'restore-recovery-input':
151
+ return { kind: 'restore-network', ownerHandle: from.ownerHandle, purpose: from.purpose }
152
+ case 'restore-ens-input':
153
+ return { kind: 'restore-recovery-input', ownerHandle: from.ownerHandle, registry: from.registry, purpose: from.purpose }
154
+ case 'restore-token-id-input':
155
+ return { kind: 'restore-recovery-input', ownerHandle: from.ownerHandle, registry: from.registry, purpose: from.purpose }
156
+ case 'restore-not-found':
149
157
  return { kind: 'restore-network', ownerHandle: from.ownerHandle, purpose: from.purpose }
150
158
  case 'restore-select-token':
151
159
  return { kind: 'restore-network', ownerHandle: from.ownerHandle, purpose: from.purpose }
152
160
  case 'restore-fetching':
153
- return { kind: 'restore-network', ownerHandle: from.candidate.ownerAddress, purpose: from.purpose }
161
+ return { kind: 'restore-network', ownerHandle: from.requesterAddress ?? from.candidate.ownerAddress, purpose: from.purpose }
154
162
  case 'restore-authorizing':
155
- return { kind: 'restore-network', ownerHandle: from.candidate.ownerAddress, purpose: from.purpose }
163
+ return { kind: 'restore-network', ownerHandle: from.requesterAddress ?? from.candidate.ownerAddress, purpose: from.purpose }
156
164
  case 'details':
157
165
  return { kind: 'menu' }
158
166
  case 'rebackup-signing':
@@ -172,21 +180,76 @@ function backStep(from: Step): Step {
172
180
  case 'edit-profile-name':
173
181
  return from.returnTo ?? { kind: 'continuity-public' }
174
182
  case 'edit-profile-description':
175
- return { kind: 'edit-profile-name', identity: from.identity, registry: from.registry, returnTo: from.returnTo }
183
+ return { kind: 'edit-profile-name', identity: from.identity, registry: from.registry, name: from.name, description: from.description, imagePath: from.imagePath, returnTo: from.returnTo }
176
184
  case 'edit-profile-image':
177
- return { kind: 'edit-profile-description', identity: from.identity, registry: from.registry, name: from.name, returnTo: from.returnTo }
185
+ return { kind: 'edit-profile-description', identity: from.identity, registry: from.registry, name: from.name, description: from.description, imagePath: from.imagePath, returnTo: from.returnTo }
186
+ case 'edit-profile-review':
187
+ return { kind: 'edit-profile-image', identity: from.identity, registry: from.registry, name: from.name, description: from.description, imagePath: from.imagePath, returnTo: from.returnTo }
188
+ case 'edit-profile-ens':
189
+ return from.returnTo ?? { kind: 'menu' }
190
+ case 'ens-records-tx':
191
+ return { kind: 'edit-profile-ens', identity: from.identity, registry: from.registry, returnTo: from.returnTo }
192
+ case 'ens-setup-registry-tx':
193
+ case 'ens-setup-records-tx':
194
+ return {
195
+ kind: 'edit-profile-ens',
196
+ identity: from.identity,
197
+ registry: from.registry,
198
+ returnTo: from.returnTo,
199
+ ...(from.setup.mode === 'advanced' ? { initialView: 'advanced' as const } : {}),
200
+ }
201
+ case 'ens-clear-flow-running':
202
+ case 'ens-update-flow-running':
203
+ return { kind: 'edit-profile-ens', identity: from.identity, registry: from.registry, returnTo: from.returnTo }
204
+ case 'ens-link-flow-running':
205
+ return {
206
+ kind: 'edit-profile-ens',
207
+ identity: from.identity,
208
+ registry: from.registry,
209
+ returnTo: from.returnTo,
210
+ ...(from.setup.mode === 'advanced' ? { initialView: 'advanced' as const } : {}),
211
+ }
212
+ case 'manage-ens-operators':
213
+ return from.returnTo ?? { kind: 'menu' }
214
+ case 'custody-model':
215
+ return from.returnTo ?? { kind: 'menu' }
216
+ case 'custody-advanced-confirm':
217
+ case 'custody-simple-confirm':
218
+ case 'custody-vault-deploy-tx':
219
+ case 'custody-vault-deposit-tx':
220
+ case 'custody-vault-unwrap-tx':
221
+ case 'custody-vault-withdraw-discovering':
222
+ case 'custody-vault-withdraw-pick-token':
223
+ case 'custody-vault-withdraw-tx':
224
+ case 'custody-vault-withdraw-done':
225
+ return { kind: 'custody-model', identity: from.identity, registry: from.registry, returnTo: from.returnTo }
226
+ case 'custody-advanced-done':
227
+ case 'custody-simple-done':
228
+ return from.returnTo ?? { kind: 'menu' }
229
+ case 'token-transfer-target':
230
+ return from.returnTo ?? { kind: 'menu' }
231
+ case 'token-transfer-resolving':
232
+ case 'token-transfer-storage':
233
+ case 'token-transfer-signing':
234
+ return { kind: 'token-transfer-target', identity: from.identity, registry: from.registry, returnTo: from.returnTo }
235
+ case 'token-transfer-ready':
236
+ return from.returnTo ?? { kind: 'menu' }
178
237
  case 'storage-credential':
179
238
  case 'storage-credential-input':
180
239
  case 'storage-credential-forget-confirm':
181
240
  return { kind: 'menu' }
241
+ case 'save-prompt':
242
+ return from.back
182
243
  case 'error':
183
244
  return from.back
245
+ case 'identity-unlinked':
246
+ return from.back
184
247
  default:
185
248
  return { kind: 'menu' }
186
249
  }
187
250
  }
188
251
 
189
- export const CREATE_STEP_LABELS = ['name', 'describe', 'network', 'create']
252
+ export const CREATE_STEP_LABELS = ['Name', 'Describe', 'Network', 'Custody', 'Create']
190
253
 
191
254
  export function createStepNumber(step: Step): number {
192
255
  switch (step.kind) {
@@ -196,11 +259,13 @@ export function createStepNumber(step: Step): number {
196
259
  return 2
197
260
  case 'create-network':
198
261
  return 3
262
+ case 'create-custody':
263
+ return 4
199
264
  case 'create-preflight':
200
265
  case 'create-storage':
201
266
  case 'create-registry':
202
267
  case 'create-signing':
203
- return 4
268
+ return 5
204
269
  default:
205
270
  return 0
206
271
  }