ethagent 2.1.0 → 2.2.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/README.md +2 -2
- package/package.json +1 -1
- package/src/auth/openaiOAuth/credentials.ts +47 -0
- package/src/auth/openaiOAuth/crypto.ts +23 -0
- package/src/auth/openaiOAuth/index.ts +238 -0
- package/src/auth/openaiOAuth/landingPage.ts +125 -0
- package/src/auth/openaiOAuth/listener.ts +151 -0
- package/src/auth/openaiOAuth/refresh.ts +70 -0
- package/src/auth/openaiOAuth/shared.ts +115 -0
- package/src/chat/chatSessionState.ts +2 -1
- package/src/chat/commands.ts +2 -1
- package/src/identity/ens/agentRecords.ts +5 -19
- package/src/identity/ens/ensAutomation/setup.ts +0 -1
- package/src/identity/ens/ensAutomation/types.ts +0 -1
- package/src/identity/hub/OperationalRoutes.tsx +2 -11
- package/src/identity/hub/components/IdentitySummary.tsx +8 -3
- package/src/identity/hub/components/MenuScreen.tsx +1 -2
- package/src/identity/hub/components/menuFlagsFromReconciliation.ts +1 -3
- package/src/identity/hub/effects/ens/transactions.ts +15 -15
- package/src/identity/hub/effects/index.ts +0 -1
- package/src/identity/hub/effects/profile/profileState.ts +12 -4
- package/src/identity/hub/effects/publicProfile/runPublicProfileSave.ts +37 -159
- package/src/identity/hub/effects/rebackup/runRebackup.ts +2 -2
- package/src/identity/hub/effects/restoreAdmin.ts +2 -61
- package/src/identity/hub/effects/shared/sync.ts +3 -44
- package/src/identity/hub/flows/custody/CustodyEditFlow.tsx +1 -39
- package/src/identity/hub/flows/custody/custodyFlowActions.ts +5 -3
- package/src/identity/hub/flows/custody/custodyFlowTypes.ts +1 -1
- package/src/identity/hub/flows/ens/EnsEditAdvancedScreens.tsx +80 -175
- package/src/identity/hub/flows/ens/EnsEditFlow.tsx +20 -75
- package/src/identity/hub/flows/ens/EnsEditMaintenanceScreens.tsx +16 -56
- package/src/identity/hub/flows/ens/EnsEditReviewScreens.tsx +0 -18
- package/src/identity/hub/flows/ens/EnsEditRunners.tsx +0 -136
- package/src/identity/hub/flows/ens/EnsEditShared.tsx +5 -4
- package/src/identity/hub/flows/ens/EnsEditSimpleScreens.tsx +56 -205
- package/src/identity/hub/flows/ens/IdentityHubEnsFlow.tsx +7 -0
- package/src/identity/hub/flows/ens/OperatorWalletsScreen.tsx +0 -31
- package/src/identity/hub/flows/ens/ensEditCopy.ts +1 -1
- package/src/identity/hub/flows/ens/ensEditTypes.ts +6 -20
- package/src/identity/hub/flows/profile/EditProfileFlow.tsx +7 -0
- package/src/identity/hub/flows/restore/RestoreFlow.tsx +5 -5
- package/src/identity/hub/reconciliation/agentReconciliation/hook.ts +0 -1
- package/src/identity/hub/reconciliation/agentReconciliation/run.ts +1 -34
- package/src/identity/hub/reconciliation/agentReconciliation/types.ts +0 -4
- package/src/identity/hub/reconciliation/index.ts +0 -7
- package/src/identity/hub/reconciliation/walletSetup.ts +1 -194
- package/src/identity/wallet/browserWallet/types.ts +0 -5
- package/src/identity/wallet/page/copy.ts +1 -31
- package/src/identity/wallet/walletPurposeCompat.ts +0 -2
- package/src/models/ModelPicker.tsx +246 -8
- package/src/models/catalog.ts +28 -1
- package/src/models/modelPickerOptions.ts +15 -1
- package/src/providers/openai-responses-format.ts +156 -0
- package/src/providers/openai-responses.ts +276 -0
- package/src/providers/registry.ts +85 -8
- package/src/runtime/systemPrompt.ts +1 -1
- package/src/runtime/turn.ts +0 -1
- package/src/storage/secrets.ts +4 -1
- package/src/tools/privateContinuityEditTool.ts +6 -0
- package/src/utils/openExternal.ts +20 -10
- package/src/identity/ens/ensRegistration.ts +0 -199
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getAddress, type Address
|
|
1
|
+
import { getAddress, type Address } from 'viem'
|
|
2
2
|
import type { EthagentIdentity } from '../../../../storage/config.js'
|
|
3
3
|
import {
|
|
4
4
|
createWalletRestoreAccessChallenge,
|
|
@@ -32,19 +32,13 @@ import { resolveValidatedPinataJwt, savePinataJwt } from '../../../storage/pinat
|
|
|
32
32
|
import {
|
|
33
33
|
openBrowserWalletSession,
|
|
34
34
|
requestBrowserWalletSignatureAndTransaction,
|
|
35
|
-
type BrowserWalletSession,
|
|
36
35
|
type BrowserWalletSignature,
|
|
37
36
|
type WalletPurpose,
|
|
38
37
|
} from '../../../wallet/browserWallet.js'
|
|
39
38
|
import type { ProfileUpdates, Step } from '../../identityHubReducer.js'
|
|
40
|
-
import { reconcileWalletSetup } from '../../reconciliation/index.js'
|
|
41
39
|
import { acquireTxGuard, releaseTxGuard } from '../../txGuard.js'
|
|
42
40
|
import type { EffectCallbacks } from '../types.js'
|
|
43
41
|
import { awaitConfirmedReceipt } from '../receipts.js'
|
|
44
|
-
import {
|
|
45
|
-
createMainnetEnsPublicClient,
|
|
46
|
-
runUpdateEnsRecords,
|
|
47
|
-
} from '../ens/transactions.js'
|
|
48
42
|
import {
|
|
49
43
|
assertVerifiedPin,
|
|
50
44
|
deriveAgentName,
|
|
@@ -55,7 +49,7 @@ import {
|
|
|
55
49
|
appendResolverSyncWarning,
|
|
56
50
|
markCurrentContinuityFilesPublished,
|
|
57
51
|
resolverSyncWarningMessage,
|
|
58
|
-
|
|
52
|
+
syncVaultOperatorsAfterOwnerSave,
|
|
59
53
|
} from '../shared/sync.js'
|
|
60
54
|
import {
|
|
61
55
|
assertSnapshotSaveSignerAuthorized,
|
|
@@ -241,7 +235,7 @@ async function runPublicProfileSigningInner(
|
|
|
241
235
|
}
|
|
242
236
|
await writePublicSkillsFile(nextIdentity, result.prepared.publicSkillsJson)
|
|
243
237
|
await markCurrentContinuityFilesPublished(nextIdentity)
|
|
244
|
-
const resolverSyncWarning = await
|
|
238
|
+
const resolverSyncWarning = await syncVaultOperatorsAfterOwnerSave({
|
|
245
239
|
beforeIdentity: step.identity,
|
|
246
240
|
afterIdentity: nextIdentity,
|
|
247
241
|
registry: step.registry,
|
|
@@ -263,92 +257,21 @@ async function runOperatorWalletPublicProfileSave(
|
|
|
263
257
|
callbacks: EffectCallbacks,
|
|
264
258
|
): Promise<void> {
|
|
265
259
|
if (!step.identity.agentId) throw new Error('Cannot update public profile: identity is missing an agent token ID')
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (!ensName) {
|
|
269
|
-
throw new Error('Operator wallet profile updates require an ENS subdomain, connect the owner wallet to set one up first')
|
|
260
|
+
if (!step.vaultAddress) {
|
|
261
|
+
throw new Error('Operator-wallet profile updates require a Vault. Set one up via Advanced Mode, or connect the owner wallet to update the profile.')
|
|
270
262
|
}
|
|
271
263
|
const snapshotOwner = ownerAddressForSnapshotSave(step.identity, step.profileUpdates)
|
|
272
264
|
const walletAccess = walletRestoreAccessContext(step.identity, step.registry, step.profileUpdates, snapshotOwner)
|
|
273
265
|
if (!walletAccess) throw new Error('Operator-wallet profile updates require wallet restore access context')
|
|
274
266
|
const challengePurpose: WalletChallengePurpose = 'restore-operator'
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
})
|
|
284
|
-
return
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const reconcileBaseState = (step.identity.state ?? {}) as Record<string, unknown>
|
|
288
|
-
const activeOperator = typeof reconcileBaseState.activeOperatorAddress === 'string'
|
|
289
|
-
? reconcileBaseState.activeOperatorAddress.trim()
|
|
290
|
-
: ''
|
|
291
|
-
if (activeOperator) {
|
|
292
|
-
const fixPlan = await reconcileWalletSetup({ identity: step.identity, registry: step.registry })
|
|
293
|
-
const stale = fixPlan.items.find(
|
|
294
|
-
(item): item is Extract<typeof item, { kind: 'missing-approval' }> =>
|
|
295
|
-
item.kind === 'missing-approval'
|
|
296
|
-
&& item.address.toLowerCase() === activeOperator.toLowerCase(),
|
|
297
|
-
)
|
|
298
|
-
if (stale) {
|
|
299
|
-
throw new Error(
|
|
300
|
-
`Operator wallet ${stale.address} is no longer approved as a resolver delegate for this agent's ENS subdomain. Connect the owner wallet and run "Fix Records" to restore the approval before retrying.`,
|
|
301
|
-
)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const session = await openBrowserWalletSession({ onReady: callbacks.onWalletReady })
|
|
306
|
-
try {
|
|
307
|
-
const wallet = await session.requestSignature({
|
|
308
|
-
chainId: step.registry.chainId,
|
|
309
|
-
messageForAccount: account => createWalletRestoreAccessChallenge({
|
|
310
|
-
token: walletAccess.token,
|
|
311
|
-
ownerAddress: snapshotOwner,
|
|
312
|
-
walletAddress: account,
|
|
313
|
-
accessEpoch: walletAccess.accessEpoch,
|
|
314
|
-
purpose: challengePurpose,
|
|
315
|
-
}),
|
|
316
|
-
purpose: 'update-profile-operator',
|
|
317
|
-
})
|
|
318
|
-
assertSnapshotSaveSignerAuthorized(step.identity, step.profileUpdates, wallet.account, snapshotOwner, walletAccess)
|
|
319
|
-
const prepared = await prepareOperatorProfileArtifacts({
|
|
320
|
-
step,
|
|
321
|
-
wallet,
|
|
322
|
-
snapshotOwner,
|
|
323
|
-
walletAccess,
|
|
324
|
-
challengePurpose,
|
|
325
|
-
includeMetadata: false,
|
|
326
|
-
})
|
|
327
|
-
await publishOperatorProfileEnsRecord({
|
|
328
|
-
ensName,
|
|
329
|
-
signer: wallet.account,
|
|
330
|
-
registry: step.registry,
|
|
331
|
-
agentCardUri: prepared.agentCardUri,
|
|
332
|
-
callbacks,
|
|
333
|
-
session,
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
await writePublicSkillsFile(prepared.nextIdentity, prepared.publicSkillsJson)
|
|
337
|
-
await markCurrentContinuityFilesPublished(prepared.nextIdentity).catch(() => null)
|
|
338
|
-
await recordPublishedContinuitySnapshot({
|
|
339
|
-
identity: prepared.nextIdentity,
|
|
340
|
-
label: 'operator-wallet ENS profile update',
|
|
341
|
-
}).catch(() => null)
|
|
342
|
-
|
|
343
|
-
await callbacks.onIdentityComplete(
|
|
344
|
-
prepared.nextIdentity,
|
|
345
|
-
'Profile pointer published to ENS records (org.ethagent.profile). ERC-8004 metadata stays put until owner wallet next signs.',
|
|
346
|
-
'update',
|
|
347
|
-
)
|
|
348
|
-
} finally {
|
|
349
|
-
await session.close().catch(() => null)
|
|
350
|
-
callbacks.onWalletReady(null)
|
|
351
|
-
}
|
|
267
|
+
await runOperatorWalletVaultPublicProfileSave({
|
|
268
|
+
step,
|
|
269
|
+
callbacks,
|
|
270
|
+
snapshotOwner,
|
|
271
|
+
walletAccess,
|
|
272
|
+
challengePurpose,
|
|
273
|
+
vaultAddress: step.vaultAddress,
|
|
274
|
+
})
|
|
352
275
|
}
|
|
353
276
|
|
|
354
277
|
type WalletAccessContext = NonNullable<ReturnType<typeof walletRestoreAccessContext>>
|
|
@@ -391,11 +314,7 @@ async function runOperatorWalletVaultPublicProfileSave(args: {
|
|
|
391
314
|
snapshotOwner,
|
|
392
315
|
walletAccess,
|
|
393
316
|
challengePurpose,
|
|
394
|
-
includeMetadata: true,
|
|
395
317
|
})
|
|
396
|
-
if (!prepared.agentUri || !prepared.metadataCid) {
|
|
397
|
-
throw new Error('Vault profile update did not prepare ERC-8004 metadata')
|
|
398
|
-
}
|
|
399
318
|
|
|
400
319
|
const vaultCall = encodeRotateAgentURI({
|
|
401
320
|
registry: getAddress(step.registry.identityRegistryAddress),
|
|
@@ -447,9 +366,8 @@ async function runOperatorWalletVaultPublicProfileSave(args: {
|
|
|
447
366
|
type OperatorProfileArtifacts = {
|
|
448
367
|
nextIdentity: EthagentIdentity
|
|
449
368
|
publicSkillsJson: string
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
metadataCid?: string
|
|
369
|
+
agentUri: string
|
|
370
|
+
metadataCid: string
|
|
453
371
|
}
|
|
454
372
|
|
|
455
373
|
async function prepareOperatorProfileArtifacts(args: {
|
|
@@ -458,7 +376,6 @@ async function prepareOperatorProfileArtifacts(args: {
|
|
|
458
376
|
snapshotOwner: Address
|
|
459
377
|
walletAccess: WalletAccessContext
|
|
460
378
|
challengePurpose: WalletChallengePurpose
|
|
461
|
-
includeMetadata: boolean
|
|
462
379
|
}): Promise<OperatorProfileArtifacts> {
|
|
463
380
|
const { step, wallet, snapshotOwner, walletAccess, challengePurpose } = args
|
|
464
381
|
const {
|
|
@@ -523,80 +440,41 @@ async function prepareOperatorProfileArtifacts(args: {
|
|
|
523
440
|
agentId: step.identity.agentId!,
|
|
524
441
|
}
|
|
525
442
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
},
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
assertVerifiedPin(metadataPin)
|
|
544
|
-
metadataCid = metadataPin.cid
|
|
545
|
-
agentUri = `ipfs://${metadataCid}`
|
|
546
|
-
}
|
|
443
|
+
const registration = withEthagentPointers({
|
|
444
|
+
type: 'https://eips.ethereum.org/EIPS/eip-8004#registration-v1',
|
|
445
|
+
name: nextName ?? deriveAgentName(step.identity),
|
|
446
|
+
...(nextDescription ? { description: nextDescription } : {}),
|
|
447
|
+
...(uploadedImageUri ? { image: uploadedImageUri } : {}),
|
|
448
|
+
}, {
|
|
449
|
+
backup: { cid: statePin.cid, envelopeVersion: envelope.envelopeVersion, createdAt: envelope.createdAt },
|
|
450
|
+
publicDiscovery: { skillsCid: publicSkills.cid, agentCardCid: publicSkills.agentCardCid, updatedAt: publicSkills.updatedAt },
|
|
451
|
+
registration: { chainId: step.registry.chainId, identityRegistryAddress: step.registry.identityRegistryAddress, agentId: step.identity.agentId },
|
|
452
|
+
ensName: nextEnsName,
|
|
453
|
+
operators: operatorsPointerFromState(state, nextEnsName),
|
|
454
|
+
ownerAddress: snapshotOwner,
|
|
455
|
+
})
|
|
456
|
+
const metadataPin = await addToIpfs(DEFAULT_IPFS_API_URL, JSON.stringify(registration, null, 2), fetch, { pinataJwt: step.pinataJwt })
|
|
457
|
+
assertVerifiedPin(metadataPin)
|
|
458
|
+
const metadataCid = metadataPin.cid
|
|
459
|
+
const agentUri = `ipfs://${metadataCid}`
|
|
547
460
|
|
|
548
|
-
const nextBackup = agentUri && metadataCid
|
|
549
|
-
? { ...backup, metadataCid, agentUri }
|
|
550
|
-
: backup
|
|
551
461
|
const nextIdentity: EthagentIdentity = {
|
|
552
462
|
...step.identity,
|
|
553
463
|
state,
|
|
554
|
-
backup:
|
|
464
|
+
backup: { ...backup, metadataCid, agentUri },
|
|
555
465
|
publicSkills,
|
|
556
|
-
|
|
557
|
-
|
|
466
|
+
agentUri,
|
|
467
|
+
metadataCid,
|
|
558
468
|
}
|
|
559
469
|
|
|
560
470
|
return {
|
|
561
471
|
nextIdentity,
|
|
562
472
|
publicSkillsJson,
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
...(metadataCid ? { metadataCid } : {}),
|
|
473
|
+
agentUri,
|
|
474
|
+
metadataCid,
|
|
566
475
|
}
|
|
567
476
|
}
|
|
568
477
|
|
|
569
|
-
async function publishOperatorProfileEnsRecord(args: {
|
|
570
|
-
ensName: string
|
|
571
|
-
signer: Address
|
|
572
|
-
registry: Erc8004RegistryConfig
|
|
573
|
-
agentCardUri: string
|
|
574
|
-
callbacks: EffectCallbacks
|
|
575
|
-
session: BrowserWalletSession
|
|
576
|
-
flowId?: string
|
|
577
|
-
flowStep?: number
|
|
578
|
-
}): Promise<void> {
|
|
579
|
-
const ensClient = createMainnetEnsPublicClient()
|
|
580
|
-
const tx = await runUpdateEnsRecords({
|
|
581
|
-
fullName: args.ensName,
|
|
582
|
-
ownerAddress: args.signer,
|
|
583
|
-
records: { profile: args.agentCardUri },
|
|
584
|
-
callbacks: args.callbacks,
|
|
585
|
-
purpose: 'update-profile-operator',
|
|
586
|
-
tokenChainId: args.registry.chainId,
|
|
587
|
-
session: args.session,
|
|
588
|
-
publicClient: ensClient,
|
|
589
|
-
...(args.flowId ? { flowId: args.flowId } : {}),
|
|
590
|
-
...(typeof args.flowStep === 'number' ? { flowStep: args.flowStep } : {}),
|
|
591
|
-
})
|
|
592
|
-
await awaitConfirmedReceipt(
|
|
593
|
-
ensClient,
|
|
594
|
-
tx.txHash as Hex,
|
|
595
|
-
'Public profile ENS record update',
|
|
596
|
-
{ kind: 'public-profile', chainId: 1 },
|
|
597
|
-
)
|
|
598
|
-
}
|
|
599
|
-
|
|
600
478
|
async function assertVaultSignerCanRotateAgentUri(args: {
|
|
601
479
|
registry: Erc8004RegistryConfig
|
|
602
480
|
vaultAddress: Address
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
appendResolverSyncWarning,
|
|
64
64
|
markCurrentContinuityFilesPublished,
|
|
65
65
|
resolverSyncWarningMessage,
|
|
66
|
-
|
|
66
|
+
syncVaultOperatorsAfterOwnerSave,
|
|
67
67
|
} from '../shared/sync.js'
|
|
68
68
|
import { runOperatorWalletRebackup } from './vault.js'
|
|
69
69
|
|
|
@@ -360,7 +360,7 @@ async function runRebackupSigningInner(
|
|
|
360
360
|
}
|
|
361
361
|
await recordPublishedContinuitySnapshot({ identity: nextIdentity, label: 'published encrypted snapshot' }).catch(() => null)
|
|
362
362
|
await markCurrentContinuityFilesPublished(nextIdentity).catch(() => null)
|
|
363
|
-
const resolverSyncWarning = await
|
|
363
|
+
const resolverSyncWarning = await syncVaultOperatorsAfterOwnerSave({
|
|
364
364
|
beforeIdentity: step.identity,
|
|
365
365
|
afterIdentity: nextIdentity,
|
|
366
366
|
registry: step.registry,
|
|
@@ -1,24 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { EthagentConfig, EthagentIdentity } from '../../../storage/config.js'
|
|
1
|
+
import type { EthagentConfig } from '../../../storage/config.js'
|
|
3
2
|
import { saveConfig } from '../../../storage/config.js'
|
|
4
|
-
import {
|
|
5
|
-
normalizeErc8004RegistryConfig,
|
|
6
|
-
type Erc8004RegistryConfig,
|
|
7
|
-
} from '../../registry/erc8004.js'
|
|
3
|
+
import { normalizeErc8004RegistryConfig } from '../../registry/erc8004.js'
|
|
8
4
|
import { registryConfigFromConfig } from '../../registry/registryConfig.js'
|
|
9
|
-
import { readOwnerAddressField } from '../../identityCompat.js'
|
|
10
|
-
import {
|
|
11
|
-
sendBrowserWalletTransaction,
|
|
12
|
-
} from '../../wallet/browserWallet.js'
|
|
13
|
-
import {
|
|
14
|
-
encodeResolverApprovalChanges,
|
|
15
|
-
verifyResolverApprovalsLanded,
|
|
16
|
-
type RecordsFixPlan,
|
|
17
|
-
} from '../reconciliation/index.js'
|
|
18
5
|
import type { Step } from '../identityHubReducer.js'
|
|
19
6
|
import type { EffectCallbacks } from './types.js'
|
|
20
|
-
import { awaitOptionalReceipt } from './receipts.js'
|
|
21
|
-
import { createMainnetEnsPublicClient } from './ens/transactions.js'
|
|
22
7
|
|
|
23
8
|
export async function runRestoreRegistrySubmit(
|
|
24
9
|
value: string,
|
|
@@ -47,47 +32,3 @@ export async function runRestoreRegistrySubmit(
|
|
|
47
32
|
}
|
|
48
33
|
callbacks.onStep({ kind: 'restore-discovering', ownerHandle: step.ownerHandle, registry, purpose: step.purpose })
|
|
49
34
|
}
|
|
50
|
-
|
|
51
|
-
export async function runFixRecordsSubmit(args: {
|
|
52
|
-
identity: EthagentIdentity
|
|
53
|
-
registry: Erc8004RegistryConfig
|
|
54
|
-
plan: RecordsFixPlan
|
|
55
|
-
callbacks: EffectCallbacks
|
|
56
|
-
}): Promise<void> {
|
|
57
|
-
const baseState = (args.identity.state ?? {}) as Record<string, unknown>
|
|
58
|
-
const ensName = args.plan.ensName ?? (typeof baseState.ensName === 'string' ? baseState.ensName.trim() : '')
|
|
59
|
-
if (!ensName) throw new Error('Cannot fix records: identity has no ENS subdomain')
|
|
60
|
-
const missing: Address[] = []
|
|
61
|
-
const stale: Address[] = []
|
|
62
|
-
for (const item of args.plan.items) {
|
|
63
|
-
if (item.kind === 'missing-approval') missing.push(item.address)
|
|
64
|
-
else if (item.kind === 'stale-approval') stale.push(item.address)
|
|
65
|
-
}
|
|
66
|
-
if (missing.length === 0 && stale.length === 0) return
|
|
67
|
-
const encoded = await encodeResolverApprovalChanges({
|
|
68
|
-
ensName,
|
|
69
|
-
diff: { added: missing, removed: stale },
|
|
70
|
-
})
|
|
71
|
-
if (!encoded) return
|
|
72
|
-
const ownerAddressRaw = readOwnerAddressField(baseState) ?? args.identity.ownerAddress ?? args.identity.address
|
|
73
|
-
const ownerAddress = getAddress(ownerAddressRaw)
|
|
74
|
-
const tx = await sendBrowserWalletTransaction({
|
|
75
|
-
chainId: 1,
|
|
76
|
-
expectedAccount: ownerAddress,
|
|
77
|
-
to: encoded.resolverAddress,
|
|
78
|
-
data: encoded.data,
|
|
79
|
-
onReady: args.callbacks.onWalletReady,
|
|
80
|
-
purpose: 'reconcile-resolver-approvals',
|
|
81
|
-
})
|
|
82
|
-
args.callbacks.onWalletReady(null)
|
|
83
|
-
const client = createMainnetEnsPublicClient()
|
|
84
|
-
await awaitOptionalReceipt(client, tx.txHash, 'Resolver approval reconciliation')
|
|
85
|
-
await verifyResolverApprovalsLanded({
|
|
86
|
-
ensName,
|
|
87
|
-
ownerAddress: ownerAddress,
|
|
88
|
-
resolverAddress: encoded.resolverAddress,
|
|
89
|
-
added: encoded.added,
|
|
90
|
-
removed: encoded.removed,
|
|
91
|
-
client,
|
|
92
|
-
})
|
|
93
|
-
}
|
|
@@ -9,14 +9,9 @@ import {
|
|
|
9
9
|
encodeSetMetadataOperator,
|
|
10
10
|
readMetadataOperators,
|
|
11
11
|
} from '../../../registry/vault.js'
|
|
12
|
-
import {
|
|
13
|
-
sendBrowserWalletTransaction,
|
|
14
|
-
type WalletPurpose,
|
|
15
|
-
} from '../../../wallet/browserWallet.js'
|
|
12
|
+
import { sendBrowserWalletTransaction } from '../../../wallet/browserWallet.js'
|
|
16
13
|
import {
|
|
17
14
|
computeApprovalDiff,
|
|
18
|
-
encodeResolverApprovalChanges,
|
|
19
|
-
verifyResolverApprovalsLanded,
|
|
20
15
|
type ApprovalDiff,
|
|
21
16
|
} from '../../reconciliation/index.js'
|
|
22
17
|
import { normalizeApprovedOperatorWallets } from '../../operatorWallets.js'
|
|
@@ -24,8 +19,7 @@ import { readOwnerAddressField } from '../../../identityCompat.js'
|
|
|
24
19
|
import { localContinuitySnapshotContentHashes } from '../../../continuity/storage.js'
|
|
25
20
|
import { updatePublishedContinuitySnapshotContentHashes } from '../../../continuity/snapshots.js'
|
|
26
21
|
import type { EffectCallbacks } from '../types.js'
|
|
27
|
-
import { awaitConfirmedReceipt
|
|
28
|
-
import { createMainnetEnsPublicClient } from '../ens/transactions.js'
|
|
22
|
+
import { awaitConfirmedReceipt } from '../receipts.js'
|
|
29
23
|
|
|
30
24
|
export function resolverSyncWarningMessage(err: unknown): string {
|
|
31
25
|
return err instanceof Error ? err.message : String(err)
|
|
@@ -36,7 +30,7 @@ export function appendResolverSyncWarning(message: string, warning: string | nul
|
|
|
36
30
|
return `${message}\n\nWarning: ${warning}`
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
export async function
|
|
33
|
+
export async function syncVaultOperatorsAfterOwnerSave(args: {
|
|
40
34
|
beforeIdentity: EthagentIdentity
|
|
41
35
|
afterIdentity: EthagentIdentity
|
|
42
36
|
registry: Erc8004RegistryConfig
|
|
@@ -45,7 +39,6 @@ export async function syncResolverApprovalsAfterOwnerSave(args: {
|
|
|
45
39
|
}): Promise<void> {
|
|
46
40
|
const beforeState = (args.beforeIdentity.state ?? {}) as Record<string, unknown>
|
|
47
41
|
const afterState = (args.afterIdentity.state ?? {}) as Record<string, unknown>
|
|
48
|
-
const ensName = typeof afterState.ensName === 'string' ? afterState.ensName.trim() : ''
|
|
49
42
|
const before = normalizeApprovedOperatorWallets(beforeState.approvedOperatorWallets)
|
|
50
43
|
const after = normalizeApprovedOperatorWallets(afterState.approvedOperatorWallets)
|
|
51
44
|
const diff = computeApprovalDiff(before, after)
|
|
@@ -54,40 +47,6 @@ export async function syncResolverApprovalsAfterOwnerSave(args: {
|
|
|
54
47
|
const ownerAddressRaw = readOwnerAddressField(afterState) ?? args.afterIdentity.ownerAddress ?? args.afterIdentity.address
|
|
55
48
|
const ownerAddress = getAddress(ownerAddressRaw)
|
|
56
49
|
|
|
57
|
-
if (ensName) {
|
|
58
|
-
let encoded
|
|
59
|
-
try {
|
|
60
|
-
encoded = await encodeResolverApprovalChanges({ ensName, diff })
|
|
61
|
-
} catch {
|
|
62
|
-
encoded = null
|
|
63
|
-
}
|
|
64
|
-
if (encoded) {
|
|
65
|
-
const purpose: WalletPurpose = diff.removed.length > 0 && diff.added.length === 0
|
|
66
|
-
? 'revoke-operator-wallet-resolver'
|
|
67
|
-
: 'authorize-operator-wallet-resolver'
|
|
68
|
-
|
|
69
|
-
const tx = await sendBrowserWalletTransaction({
|
|
70
|
-
chainId: 1,
|
|
71
|
-
expectedAccount: ownerAddress,
|
|
72
|
-
to: encoded.resolverAddress,
|
|
73
|
-
data: encoded.data,
|
|
74
|
-
onReady: args.callbacks.onWalletReady,
|
|
75
|
-
purpose,
|
|
76
|
-
})
|
|
77
|
-
args.callbacks.onWalletReady(null)
|
|
78
|
-
const client = createMainnetEnsPublicClient()
|
|
79
|
-
await awaitOptionalReceipt(client, tx.txHash, 'Resolver delegation sync')
|
|
80
|
-
await verifyResolverApprovalsLanded({
|
|
81
|
-
ensName,
|
|
82
|
-
ownerAddress: ownerAddress,
|
|
83
|
-
resolverAddress: encoded.resolverAddress,
|
|
84
|
-
added: encoded.added,
|
|
85
|
-
removed: encoded.removed,
|
|
86
|
-
client,
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
50
|
await syncVaultMetadataOperatorsAfterOwnerSave({
|
|
92
51
|
afterIdentity: args.afterIdentity,
|
|
93
52
|
registry: args.registry,
|
|
@@ -15,11 +15,7 @@ import { ensValidationReasonText, selectEnsStatus } from '../../model/ens.js'
|
|
|
15
15
|
import { shortAddress } from '../../model/format.js'
|
|
16
16
|
import { lastBackupLabel } from '../../model/identity.js'
|
|
17
17
|
import {
|
|
18
|
-
describeFixPlanItem,
|
|
19
|
-
fixPlanRequiresOwnerWallet,
|
|
20
|
-
reconcileWalletSetup,
|
|
21
18
|
type AgentReconciliation,
|
|
22
|
-
type RecordsFixPlan,
|
|
23
19
|
} from '../../reconciliation/index.js'
|
|
24
20
|
|
|
25
21
|
const footerHint = (hint: string) => <Text color={theme.dim}>{hint}</Text>
|
|
@@ -37,7 +33,6 @@ interface CustodyEditFlowProps {
|
|
|
37
33
|
onReturnToVault: (returnTo: Step, vaultAddress: Address) => void
|
|
38
34
|
onResumeAdvanced: (returnTo: Step) => void
|
|
39
35
|
onManageOperatorWallets: () => void
|
|
40
|
-
onFixRecords: (plan: RecordsFixPlan) => void
|
|
41
36
|
onPrepareTransfer: () => void
|
|
42
37
|
onBack: () => void
|
|
43
38
|
}
|
|
@@ -59,7 +54,6 @@ export const CustodyEditFlow: React.FC<CustodyEditFlowProps> = ({
|
|
|
59
54
|
onReturnToVault,
|
|
60
55
|
onResumeAdvanced,
|
|
61
56
|
onManageOperatorWallets,
|
|
62
|
-
onFixRecords,
|
|
63
57
|
onPrepareTransfer,
|
|
64
58
|
onBack,
|
|
65
59
|
}) => {
|
|
@@ -77,19 +71,8 @@ export const CustodyEditFlow: React.FC<CustodyEditFlowProps> = ({
|
|
|
77
71
|
const tokenLabel = identity.agentId ? `Token #${identity.agentId}` : 'Token #unknown'
|
|
78
72
|
const tokenOwner = identity.ownerAddress ?? identity.address
|
|
79
73
|
|
|
80
|
-
const [fixPlan, setFixPlan] = React.useState<RecordsFixPlan | null>(null)
|
|
81
|
-
React.useEffect(() => {
|
|
82
|
-
if (step.kind !== 'custody-model') return
|
|
83
|
-
if (custodyMode !== 'advanced') return
|
|
84
|
-
let cancelled = false
|
|
85
|
-
reconcileWalletSetup({ identity, registry })
|
|
86
|
-
.then(plan => { if (!cancelled) setFixPlan(plan) })
|
|
87
|
-
.catch(() => { if (!cancelled) setFixPlan(null) })
|
|
88
|
-
return () => { cancelled = true }
|
|
89
|
-
}, [identity, registry, step.kind, custodyMode])
|
|
90
|
-
|
|
91
74
|
if (step.kind === 'custody-model') {
|
|
92
|
-
type Action = 'switch-advanced' | 'switch-simple' | 'resume-advanced' | 'cancel-advanced' | 'withdraw-token' | 'return-to-vault' | 'manage-operator-wallets' | '
|
|
75
|
+
type Action = 'switch-advanced' | 'switch-simple' | 'resume-advanced' | 'cancel-advanced' | 'withdraw-token' | 'return-to-vault' | 'manage-operator-wallets' | 'back'
|
|
93
76
|
const onChainCustody = reconciliation?.custody
|
|
94
77
|
const midFlow = onChainCustody === 'mid-flow-uri-pending'
|
|
95
78
|
const isAdvanced = onChainCustody === 'advanced' || midFlow || custodyMode === 'advanced'
|
|
@@ -149,15 +132,6 @@ export const CustodyEditFlow: React.FC<CustodyEditFlowProps> = ({
|
|
|
149
132
|
hint: 'Add or revoke wallets that can publish updates onchain.',
|
|
150
133
|
})
|
|
151
134
|
}
|
|
152
|
-
const hasFixablePlan = fixPlan !== null && fixPlanRequiresOwnerWallet(fixPlan)
|
|
153
|
-
if (hasFixablePlan) {
|
|
154
|
-
options.push({ value: 'fix-records', role: 'section', label: 'Records Out Of Sync' })
|
|
155
|
-
options.push({
|
|
156
|
-
value: 'fix-records',
|
|
157
|
-
label: 'Fix Records (Owner Wallet)',
|
|
158
|
-
hint: 'Sync ENS resolver approvals with the operator wallet list.',
|
|
159
|
-
})
|
|
160
|
-
}
|
|
161
135
|
options.push({ value: 'back', role: 'section', label: 'Navigation' })
|
|
162
136
|
options.push({ value: 'back', label: 'Back', hint: 'Return to Identity Hub', role: 'utility' })
|
|
163
137
|
const notice = step.kind === 'custody-model' ? step.notice : undefined
|
|
@@ -201,14 +175,6 @@ export const CustodyEditFlow: React.FC<CustodyEditFlowProps> = ({
|
|
|
201
175
|
return <Row label="Last Saved" value={lastBackup} muted={lastBackup === 'never'} />
|
|
202
176
|
})()}
|
|
203
177
|
</Box>
|
|
204
|
-
{fixPlan && fixPlan.items.length > 0 ? (
|
|
205
|
-
<Box marginTop={1} flexDirection="column">
|
|
206
|
-
<Text color={theme.accentPeriwinkle} bold>Records out of sync:</Text>
|
|
207
|
-
{fixPlan.items.map((item, idx) => (
|
|
208
|
-
<Text key={idx} color={theme.dim}>· {describeFixPlanItem(item)}</Text>
|
|
209
|
-
))}
|
|
210
|
-
</Box>
|
|
211
|
-
) : null}
|
|
212
178
|
<Box marginTop={1}>
|
|
213
179
|
<Select<Action>
|
|
214
180
|
options={options}
|
|
@@ -226,10 +192,6 @@ export const CustodyEditFlow: React.FC<CustodyEditFlowProps> = ({
|
|
|
226
192
|
onSetStep({ kind: 'custody-simple-confirm', identity, registry, returnTo })
|
|
227
193
|
return
|
|
228
194
|
}
|
|
229
|
-
if (choice === 'fix-records') {
|
|
230
|
-
if (fixPlan) onFixRecords(fixPlan)
|
|
231
|
-
return
|
|
232
|
-
}
|
|
233
195
|
if (choice === 'switch-advanced') {
|
|
234
196
|
onSetStep({ kind: 'custody-advanced-confirm', identity, registry, returnTo })
|
|
235
197
|
return
|
|
@@ -16,7 +16,7 @@ export function createCustodyFlowActions({
|
|
|
16
16
|
}: CustodyFlowDeps): {
|
|
17
17
|
beginVaultDeposit: (currentStep: Step, returnTo: Step, profileUpdates: ProfileUpdates) => void
|
|
18
18
|
beginVaultUnwrap: (currentStep: Step, returnTo: Step, profileUpdates: ProfileUpdates) => void
|
|
19
|
-
beginWithdrawToken: (currentStep: Step, returnTo: Step) => void
|
|
19
|
+
beginWithdrawToken: (currentStep: Step, returnTo: Step, returnContext?: 'ens' | 'simple-exit') => void
|
|
20
20
|
beginReturnToVault: (currentStep: Step, returnTo: Step, vaultAddress: Address) => void
|
|
21
21
|
} {
|
|
22
22
|
const beginVaultDeposit = (currentStep: Step, returnTo: Step, profileUpdates: ProfileUpdates): void => {
|
|
@@ -122,8 +122,8 @@ export function createCustodyFlowActions({
|
|
|
122
122
|
})()
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
const beginWithdrawToken = (currentStep: Step, returnTo: Step): void => {
|
|
126
|
-
if (!isCustodyEditStep(currentStep)) return
|
|
125
|
+
const beginWithdrawToken = (currentStep: Step, returnTo: Step, returnContext?: 'ens' | 'simple-exit'): void => {
|
|
126
|
+
if (!isCustodyEditStep(currentStep) && currentStep.kind !== 'edit-profile-ens') return
|
|
127
127
|
const vaultAddress = resolveVaultAddress(currentStep.identity, config?.erc8004?.operatorVaults)
|
|
128
128
|
if (!vaultAddress) {
|
|
129
129
|
handleStepError(
|
|
@@ -147,6 +147,7 @@ export function createCustodyFlowActions({
|
|
|
147
147
|
registry: currentStep.registry,
|
|
148
148
|
vaultAddress,
|
|
149
149
|
returnTo,
|
|
150
|
+
...(returnContext ? { returnContext } : {}),
|
|
150
151
|
})
|
|
151
152
|
;(async () => {
|
|
152
153
|
const client = createErc8004PublicClient(currentStep.registry)
|
|
@@ -172,6 +173,7 @@ export function createCustodyFlowActions({
|
|
|
172
173
|
vaultAddress,
|
|
173
174
|
agentId: activeAgentId,
|
|
174
175
|
returnTo,
|
|
176
|
+
...(returnContext ? { returnContext } : {}),
|
|
175
177
|
})
|
|
176
178
|
return
|
|
177
179
|
}
|
|
@@ -35,7 +35,7 @@ export interface CustodyFlowDeps {
|
|
|
35
35
|
export interface CustodyFlow {
|
|
36
36
|
beginVaultDeposit: (currentStep: Step, returnTo: Step, profileUpdates: ProfileUpdates) => void
|
|
37
37
|
beginVaultUnwrap: (currentStep: Step, returnTo: Step, profileUpdates: ProfileUpdates) => void
|
|
38
|
-
beginWithdrawToken: (currentStep: Step, returnTo: Step) => void
|
|
38
|
+
beginWithdrawToken: (currentStep: Step, returnTo: Step, returnContext?: 'ens' | 'simple-exit') => void
|
|
39
39
|
beginReturnToVault: (currentStep: Step, returnTo: Step, vaultAddress: Address) => void
|
|
40
40
|
renderCustodyStep: () => React.ReactElement | null
|
|
41
41
|
renderRebackupSubtitle: (
|