ethagent 3.2.0 → 3.3.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 +15 -16
- package/package.json +1 -1
- package/src/identity/continuity/history.ts +8 -8
- package/src/identity/continuity/publicSkills.ts +2 -79
- package/src/identity/continuity/skills/publicSkillsSync.ts +8 -7
- package/src/identity/continuity/snapshots.ts +3 -8
- package/src/identity/continuity/storage/defaults.ts +3 -3
- package/src/identity/continuity/storage/paths.ts +1 -1
- package/src/identity/continuity/storage/scaffold.ts +37 -25
- package/src/identity/continuity/storage/status.ts +11 -11
- package/src/identity/continuity/storage/types.ts +4 -4
- package/src/identity/continuity/storage.ts +4 -4
- package/src/identity/ens/agentRecords.ts +61 -45
- package/src/identity/ens/ensAutomation/read.ts +7 -10
- package/src/identity/ens/ensAutomation/setup.ts +10 -16
- package/src/identity/ens/ensAutomation/types.ts +0 -1
- package/src/identity/ens/ensAutomation.ts +1 -0
- package/src/identity/ens/ensLookup/records.ts +1 -1
- package/src/identity/ens/ensLookup.ts +1 -1
- package/src/identity/ens/erc7930.ts +48 -0
- package/src/identity/hub/OperationalRoutes.tsx +4 -1
- package/src/identity/hub/continuity/effects.ts +17 -39
- package/src/identity/hub/continuity/skills/NewSkillVisibilityScreen.tsx +2 -2
- package/src/identity/hub/continuity/skills/SkillActionsScreen.tsx +2 -2
- package/src/identity/hub/continuity/state.ts +1 -1
- package/src/identity/hub/continuity/vault.ts +16 -50
- package/src/identity/hub/create/effects.ts +12 -16
- package/src/identity/hub/ens/EnsEditFlow.tsx +19 -5
- package/src/identity/hub/ens/EnsEditReviewScreens.tsx +11 -11
- package/src/identity/hub/ens/EnsEditShared.tsx +2 -6
- package/src/identity/hub/ens/editCopy.ts +1 -3
- package/src/identity/hub/ens/transactions.ts +67 -18
- package/src/identity/hub/profile/effects.ts +15 -30
- package/src/identity/hub/profile/identity.ts +2 -4
- package/src/identity/hub/profile/operatorSave.ts +10 -30
- package/src/identity/hub/restore/RestoreFlow.tsx +9 -9
- package/src/identity/hub/restore/apply.ts +7 -8
- package/src/identity/hub/restore/helpers.ts +3 -3
- package/src/identity/hub/restore/recovery.ts +9 -10
- package/src/identity/hub/restore/resolve.ts +11 -9
- package/src/identity/hub/shared/components/MenuScreen.tsx +3 -3
- package/src/identity/hub/shared/components/UnlinkedIdentityScreen.tsx +2 -2
- package/src/identity/hub/shared/effects/sync.ts +1 -1
- package/src/identity/hub/transfer/TokenTransferScreens.tsx +1 -1
- package/src/identity/hub/transfer/effects.ts +10 -31
- package/src/identity/hub/useIdentityHubContinuity.ts +12 -12
- package/src/identity/hub/useIdentityHubController.ts +12 -3
- package/src/identity/registry/erc8004/metadata.ts +10 -27
- package/src/identity/registry/erc8004/types.ts +0 -1
- package/src/storage/config.ts +1 -2
- package/src/storage/identity.ts +3 -3
- package/src/storage/rewind.ts +1 -1
- package/src/tools/privateContinuityEditTool.ts +4 -4
- package/src/utils/withRetry.ts +2 -2
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
createAgentCard,
|
|
16
16
|
defaultPublicSkillsProfile,
|
|
17
|
-
renderPublicSkillsJson,
|
|
18
17
|
serializeAgentCard,
|
|
19
18
|
} from '../../continuity/publicSkills.js'
|
|
20
19
|
import { recordPublishedContinuitySnapshot } from '../../continuity/snapshots.js'
|
|
@@ -43,17 +42,17 @@ import { awaitConfirmedReceipt } from '../shared/effects/receipts.js'
|
|
|
43
42
|
import { assertVerifiedPin } from '../shared/effects/profilePrep.js'
|
|
44
43
|
|
|
45
44
|
type BackupMetadata = NonNullable<EthagentIdentity['backup']>
|
|
46
|
-
type
|
|
45
|
+
type AgentCardMetadata = NonNullable<EthagentIdentity['agentCard']>
|
|
47
46
|
|
|
48
47
|
type CreatePreparedTransaction = {
|
|
49
48
|
ownerAddress: Address
|
|
50
49
|
agentUri: string
|
|
51
50
|
metadataCid: string
|
|
52
51
|
backup: BackupMetadata
|
|
53
|
-
|
|
52
|
+
agentCard: AgentCardMetadata
|
|
54
53
|
state: Record<string, unknown>
|
|
55
54
|
continuityFiles: ReturnType<typeof defaultContinuityFiles>
|
|
56
|
-
|
|
55
|
+
agentCardJson: string
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
export async function runCreatePreflight(
|
|
@@ -139,10 +138,8 @@ export async function runCreateSigning(
|
|
|
139
138
|
})
|
|
140
139
|
const continuityFiles = defaultContinuityFiles(draftIdentity)
|
|
141
140
|
const publicProfile = defaultPublicSkillsProfile(draftIdentity)
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
assertVerifiedPin(publicSkillsPin)
|
|
145
|
-
const agentCardPin = await addToIpfs(DEFAULT_IPFS_API_URL, serializeAgentCard(createAgentCard(publicProfile)), fetch, { pinataJwt: step.pinataJwt })
|
|
141
|
+
const agentCardJson = serializeAgentCard(createAgentCard(publicProfile))
|
|
142
|
+
const agentCardPin = await addToIpfs(DEFAULT_IPFS_API_URL, agentCardJson, fetch, { pinataJwt: step.pinataJwt })
|
|
146
143
|
assertVerifiedPin(agentCardPin)
|
|
147
144
|
const envelope = createContinuitySnapshotEnvelope({
|
|
148
145
|
ownerAddress: wallet.account,
|
|
@@ -168,9 +165,8 @@ export async function runCreateSigning(
|
|
|
168
165
|
rpcUrl: step.registry.rpcUrl,
|
|
169
166
|
identityRegistryAddress: step.registry.identityRegistryAddress,
|
|
170
167
|
}
|
|
171
|
-
const
|
|
172
|
-
cid:
|
|
173
|
-
agentCardCid: agentCardPin.cid,
|
|
168
|
+
const agentCard: AgentCardMetadata = {
|
|
169
|
+
cid: agentCardPin.cid,
|
|
174
170
|
updatedAt: envelope.createdAt,
|
|
175
171
|
status: 'pinned',
|
|
176
172
|
}
|
|
@@ -181,7 +177,7 @@ export async function runCreateSigning(
|
|
|
181
177
|
...(typeof state.imageUrl === 'string' ? { image: state.imageUrl } : {}),
|
|
182
178
|
}, {
|
|
183
179
|
backup: { cid, envelopeVersion: envelope.envelopeVersion, createdAt: envelope.createdAt },
|
|
184
|
-
publicDiscovery: {
|
|
180
|
+
publicDiscovery: { agentCardCid: agentCard.cid, updatedAt: agentCard.updatedAt },
|
|
185
181
|
registration: { chainId: step.registry.chainId, identityRegistryAddress: step.registry.identityRegistryAddress },
|
|
186
182
|
ownerAddress: wallet.account,
|
|
187
183
|
})
|
|
@@ -197,10 +193,10 @@ export async function runCreateSigning(
|
|
|
197
193
|
agentUri,
|
|
198
194
|
metadataCid,
|
|
199
195
|
backup: { ...backup, metadataCid, agentUri },
|
|
200
|
-
|
|
196
|
+
agentCard,
|
|
201
197
|
state,
|
|
202
198
|
continuityFiles,
|
|
203
|
-
|
|
199
|
+
agentCardJson,
|
|
204
200
|
},
|
|
205
201
|
}
|
|
206
202
|
},
|
|
@@ -233,11 +229,11 @@ export async function runCreateSigning(
|
|
|
233
229
|
metadataCid: result.prepared.metadataCid,
|
|
234
230
|
state: result.prepared.state,
|
|
235
231
|
backup,
|
|
236
|
-
|
|
232
|
+
agentCard: result.prepared.agentCard,
|
|
237
233
|
}
|
|
238
234
|
await writeIdentityMarkdownScaffold(nextIdentity, {
|
|
239
235
|
...defaultContinuityFiles(nextIdentity),
|
|
240
|
-
'
|
|
236
|
+
'agent-card.json': result.prepared.agentCardJson,
|
|
241
237
|
})
|
|
242
238
|
await recordPublishedContinuitySnapshot({ identity: nextIdentity, label: 'initial published snapshot' }).catch(() => null)
|
|
243
239
|
await callbacks.onIdentityComplete(nextIdentity, `ERC-8004 agent registered · #${registered.agentId.toString()}`, 'create')
|
|
@@ -2,8 +2,8 @@ import React from 'react'
|
|
|
2
2
|
import { getAddress, type Address } from 'viem'
|
|
3
3
|
import type { BrowserWalletReady } from '../../wallet/browserWallet.js'
|
|
4
4
|
import {
|
|
5
|
-
AGENT_RECORD_READ_KEY_LIST,
|
|
6
5
|
buildAgentEnsRecords,
|
|
6
|
+
buildEnsip25Key,
|
|
7
7
|
diffRecords,
|
|
8
8
|
recordsFromTextMap,
|
|
9
9
|
} from '../../ens/agentRecords.js'
|
|
@@ -137,8 +137,15 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
|
|
|
137
137
|
setPhase({ kind: 'validating', fullName, mode, ownerAddress: phaseOwnerAddress, operatorWallet })
|
|
138
138
|
try {
|
|
139
139
|
const validation = await validateAgentEnsLink(fullName, ownerAddress)
|
|
140
|
-
const
|
|
141
|
-
?
|
|
140
|
+
const readKeys = identity.agentId
|
|
141
|
+
? [buildEnsip25Key({
|
|
142
|
+
chainId: registry.chainId,
|
|
143
|
+
identityRegistryAddress: registry.identityRegistryAddress,
|
|
144
|
+
agentId: identity.agentId,
|
|
145
|
+
})]
|
|
146
|
+
: []
|
|
147
|
+
const currentText = validation.ok && readKeys.length > 0
|
|
148
|
+
? await readEthagentTextRecords(fullName, readKeys)
|
|
142
149
|
: {}
|
|
143
150
|
const current = recordsFromTextMap(currentText)
|
|
144
151
|
const next = buildAgentEnsRecords({
|
|
@@ -252,7 +259,14 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
|
|
|
252
259
|
const runUnlinkEnsLoading = React.useCallback((fullName: string): void => {
|
|
253
260
|
setValidationError(null)
|
|
254
261
|
setPhase({ kind: 'unlink-loading', fullName })
|
|
255
|
-
|
|
262
|
+
const readKeys = identity.agentId
|
|
263
|
+
? [buildEnsip25Key({
|
|
264
|
+
chainId: registry.chainId,
|
|
265
|
+
identityRegistryAddress: registry.identityRegistryAddress,
|
|
266
|
+
agentId: identity.agentId,
|
|
267
|
+
})]
|
|
268
|
+
: []
|
|
269
|
+
readEthagentTextRecords(fullName, readKeys)
|
|
256
270
|
.then(currentText => {
|
|
257
271
|
const currentRecords = recordsFromTextMap(currentText)
|
|
258
272
|
setPhase({
|
|
@@ -266,7 +280,7 @@ export const EnsEditFlow: React.FC<EnsEditProps> = ({
|
|
|
266
280
|
setValidationError(err instanceof Error ? err.message : String(err))
|
|
267
281
|
setPhase({ kind: 'mode-select' })
|
|
268
282
|
})
|
|
269
|
-
}, [])
|
|
283
|
+
}, [identity.agentId, registry.chainId, registry.identityRegistryAddress])
|
|
270
284
|
|
|
271
285
|
const maintenanceScreen = renderEnsMaintenancePhase({
|
|
272
286
|
phase,
|
|
@@ -4,11 +4,9 @@ import { getAddress, type Address } from 'viem'
|
|
|
4
4
|
import { Surface } from '../../../ui/Surface.js'
|
|
5
5
|
import { Select, type SelectOption } from '../../../ui/Select.js'
|
|
6
6
|
import { theme } from '../../../ui/theme.js'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type AgentEnsRecords,
|
|
11
|
-
type AgentRecordDiff,
|
|
7
|
+
import type {
|
|
8
|
+
AgentEnsRecords,
|
|
9
|
+
AgentRecordDiff,
|
|
12
10
|
} from '../../ens/agentRecords.js'
|
|
13
11
|
import type { EnsValidation } from '../../ens/ensLookup.js'
|
|
14
12
|
import type {
|
|
@@ -194,7 +192,9 @@ export const EnsSetupBlockedScreen: React.FC<EnsSetupBlockedScreenProps> = ({
|
|
|
194
192
|
{isSimple
|
|
195
193
|
? <EnsSetupRow label="Wallet" value={fallback.ownerAddress ? shortAddress(fallback.ownerAddress) : shortAddress(fallback.operatorAddress)} />
|
|
196
194
|
: (fallback.ownerAddress ? <EnsSetupRow label="Owner wallet" value={shortAddress(fallback.ownerAddress)} /> : null)}
|
|
197
|
-
{fallback.nextRecords
|
|
195
|
+
{fallback.nextRecords && Object.keys(fallback.nextRecords).length > 0
|
|
196
|
+
? <EnsSetupRow label="Attestation" value="ENSIP-25 agent-registration record" />
|
|
197
|
+
: null}
|
|
198
198
|
<EnsSetupRow label="Address" value={`Set the subdomain address record to the ${isSimple ? 'connected wallet' : 'owner wallet'}.`} />
|
|
199
199
|
{!isSimple
|
|
200
200
|
? (
|
|
@@ -271,7 +271,7 @@ export const UnlinkEnsReviewScreen: React.FC<UnlinkEnsReviewScreenProps> = ({
|
|
|
271
271
|
{changedDiffs.map(diff => (
|
|
272
272
|
<Text key={diff.key}>
|
|
273
273
|
<Text color={theme.dim}>{` ${diff.key} `}</Text>
|
|
274
|
-
<Text color={theme.accentPeriwinkle}>{
|
|
274
|
+
<Text color={theme.accentPeriwinkle}>{diff.current}</Text>
|
|
275
275
|
</Text>
|
|
276
276
|
))}
|
|
277
277
|
</Box>
|
|
@@ -420,16 +420,16 @@ export const ReviewScreen: React.FC<ReviewScreenProps> = ({
|
|
|
420
420
|
: null}
|
|
421
421
|
{recordsDiff.map(diff => (
|
|
422
422
|
<Text key={diff.key}>
|
|
423
|
-
<Text color={theme.dim}>{`- ${
|
|
423
|
+
<Text color={theme.dim}>{`- ${diff.key}: `}</Text>
|
|
424
424
|
{diff.changed
|
|
425
425
|
? (
|
|
426
426
|
<>
|
|
427
|
-
{renderRecordValue(diff.
|
|
427
|
+
{renderRecordValue(diff.current)}
|
|
428
428
|
<Text color={theme.dim}>{' → '}</Text>
|
|
429
|
-
{renderRecordValue(diff.
|
|
429
|
+
{renderRecordValue(diff.next)}
|
|
430
430
|
</>
|
|
431
431
|
)
|
|
432
|
-
: renderRecordValue(diff.
|
|
432
|
+
: renderRecordValue(diff.next)}
|
|
433
433
|
</Text>
|
|
434
434
|
))}
|
|
435
435
|
{!hasRecordChanges
|
|
@@ -4,10 +4,6 @@ import type { Address } from 'viem'
|
|
|
4
4
|
import { Surface } from '../../../ui/Surface.js'
|
|
5
5
|
import { TextInput } from '../../../ui/TextInput.js'
|
|
6
6
|
import { theme } from '../../../ui/theme.js'
|
|
7
|
-
import {
|
|
8
|
-
formatRecordValue,
|
|
9
|
-
type AgentEnsRecordState,
|
|
10
|
-
} from '../../ens/agentRecords.js'
|
|
11
7
|
import {
|
|
12
8
|
isEthDomain,
|
|
13
9
|
sanitizeSubdomainPrefix,
|
|
@@ -24,9 +20,9 @@ import type { EnsEditProps } from './types.js'
|
|
|
24
20
|
|
|
25
21
|
export const footerHint = (hint: string) => <Text color={theme.dim}>{hint}</Text>
|
|
26
22
|
|
|
27
|
-
export const renderRecordValue = (
|
|
23
|
+
export const renderRecordValue = (value: string) =>
|
|
28
24
|
value
|
|
29
|
-
? <Text color={theme.accentPeriwinkle}>{
|
|
25
|
+
? <Text color={theme.accentPeriwinkle}>{value}</Text>
|
|
30
26
|
: <Text color={theme.dim}>Unset</Text>
|
|
31
27
|
|
|
32
28
|
export function rootErrorMessage(
|
|
@@ -18,7 +18,7 @@ export function recordsHaveCurrentValues(recordsDiff: AgentRecordDiff[]): boolea
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function emptyAgentEnsRecords(): AgentEnsRecords {
|
|
21
|
-
return {
|
|
21
|
+
return {}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function unlinkEnsLinkOptions(savedCustodyMode: CustodyMode | undefined, savedOwnerAddress: string): EnsLinkOptions {
|
|
@@ -84,8 +84,6 @@ export function manualReasonTitle(reason: EnsSetupBlockedPlan['reason']): string
|
|
|
84
84
|
case 'wrapped-parent':
|
|
85
85
|
case 'subdomain-wrapped':
|
|
86
86
|
return 'ENS NameWrapper ownership could not be verified'
|
|
87
|
-
case 'token-record-collision':
|
|
88
|
-
return 'Subdomain already points to another token'
|
|
89
87
|
case 'token-owner-mismatch':
|
|
90
88
|
return 'Owner wallet does not own this ERC-8004 token'
|
|
91
89
|
case 'token-owner-lookup-failed':
|
|
@@ -5,10 +5,11 @@ import {
|
|
|
5
5
|
createErc8004PublicClient,
|
|
6
6
|
supportedErc8004ChainForId,
|
|
7
7
|
} from '../../registry/erc8004.js'
|
|
8
|
-
import {
|
|
9
|
-
import { encodeEnsRecordsTransaction, encodeEnsRegistryTransaction, type EnsSetupPlan } from '../../ens/ensAutomation.js'
|
|
10
|
-
import type { AgentEnsRecordState, AgentEnsRecords } from '../../ens/agentRecords.js'
|
|
11
|
-
import { changedRecords } from '../../ens/agentRecords.js'
|
|
8
|
+
import { encodeSetEnsip25TextRecord, readEthagentTextRecords } from '../../ens/ensLookup.js'
|
|
9
|
+
import { encodeEnsRecordsTransaction, encodeEnsRegistryTransaction, readAddressRecord, type EnsSetupPlan } from '../../ens/ensAutomation.js'
|
|
10
|
+
import type { AgentEnsRecordState, AgentEnsRecords, AgentRecordDiff } from '../../ens/agentRecords.js'
|
|
11
|
+
import { changedRecords, clearedRecords, diffRecords } from '../../ens/agentRecords.js'
|
|
12
|
+
import { namehash, getAddress } from 'viem'
|
|
12
13
|
import { sendBrowserWalletTransaction, type BrowserWalletSession, type WalletPurpose } from '../../wallet/browserWallet.js'
|
|
13
14
|
import type { EffectCallbacks } from '../shared/effects/types.js'
|
|
14
15
|
function chainLabel(chainId: number): string {
|
|
@@ -32,17 +33,29 @@ export async function runUpdateEnsRecords(args: {
|
|
|
32
33
|
session?: BrowserWalletSession
|
|
33
34
|
flowId?: string
|
|
34
35
|
flowStep?: number
|
|
35
|
-
}): Promise<{ txHash: string }> {
|
|
36
|
+
}): Promise<{ txHash: string } | { skipped: true }> {
|
|
37
|
+
const publicClient = args.publicClient ?? createMainnetEnsPublicClient()
|
|
38
|
+
const queryKeys = Array.from(new Set([
|
|
39
|
+
...Object.keys(args.records ?? {}),
|
|
40
|
+
...Object.keys(args.currentRecords ?? {}),
|
|
41
|
+
]))
|
|
42
|
+
let freshCurrent: AgentEnsRecordState = args.currentRecords ?? {}
|
|
43
|
+
if (queryKeys.length > 0) {
|
|
44
|
+
try {
|
|
45
|
+
freshCurrent = await readEthagentTextRecords(args.fullName, queryKeys, { publicClient })
|
|
46
|
+
} catch {
|
|
47
|
+
freshCurrent = args.currentRecords ?? {}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
36
50
|
const next = ensRecordWritesForUpdate({
|
|
37
51
|
records: args.records,
|
|
38
|
-
currentRecords:
|
|
52
|
+
currentRecords: freshCurrent,
|
|
39
53
|
clearRecords: args.clearRecords,
|
|
40
54
|
})
|
|
41
55
|
if (Object.keys(next).length === 0) {
|
|
42
|
-
|
|
56
|
+
return { skipped: true }
|
|
43
57
|
}
|
|
44
|
-
const
|
|
45
|
-
const encoded = await encodeSetEthagentTextRecords(args.fullName, next, { publicClient })
|
|
58
|
+
const encoded = await encodeSetEnsip25TextRecord(args.fullName, next, { publicClient })
|
|
46
59
|
await preflightEnsRecordTransaction({
|
|
47
60
|
fullName: args.fullName,
|
|
48
61
|
account: args.ownerAddress,
|
|
@@ -83,10 +96,11 @@ export function ensRecordWritesForUpdate(args: {
|
|
|
83
96
|
currentRecords?: AgentEnsRecordState
|
|
84
97
|
clearRecords?: boolean
|
|
85
98
|
}): Record<string, string> {
|
|
99
|
+
const current = args.currentRecords ?? {}
|
|
86
100
|
if (args.clearRecords) {
|
|
87
|
-
return changedRecords(
|
|
101
|
+
return changedRecords(current, clearedRecords(current))
|
|
88
102
|
}
|
|
89
|
-
return changedRecords(
|
|
103
|
+
return changedRecords(current, args.records)
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
export async function runEnsSetupRegistryTransaction(args: {
|
|
@@ -148,13 +162,14 @@ export async function runEnsSetupRecordsTransaction(args: {
|
|
|
148
162
|
flowId?: string
|
|
149
163
|
flowStep?: number
|
|
150
164
|
}): Promise<{ txHash: string } | null> {
|
|
151
|
-
const encoded = encodeEnsRecordsTransaction(args.setup)
|
|
152
|
-
if (!encoded) return null
|
|
153
165
|
const publicClient = args.publicClient ?? createMainnetEnsPublicClient()
|
|
154
|
-
const
|
|
166
|
+
const freshSetup = await refreshEnsSetupAgainstChain(args.setup, publicClient)
|
|
167
|
+
const encoded = encodeEnsRecordsTransaction(freshSetup)
|
|
168
|
+
if (!encoded) return null
|
|
169
|
+
const purpose: WalletPurpose = freshSetup.mode === 'simple' ? 'set-simple-ens-records' : 'set-agent-ens-records'
|
|
155
170
|
await preflightEnsRecordTransaction({
|
|
156
|
-
fullName:
|
|
157
|
-
account:
|
|
171
|
+
fullName: freshSetup.fullName,
|
|
172
|
+
account: freshSetup.ownerAddress,
|
|
158
173
|
to: encoded.to,
|
|
159
174
|
data: encoded.data,
|
|
160
175
|
publicClient,
|
|
@@ -164,7 +179,7 @@ export async function runEnsSetupRecordsTransaction(args: {
|
|
|
164
179
|
if (args.session) {
|
|
165
180
|
const result = await args.session.sendTransaction({
|
|
166
181
|
chainId: 1,
|
|
167
|
-
expectedAccount:
|
|
182
|
+
expectedAccount: freshSetup.ownerAddress,
|
|
168
183
|
to: encoded.to,
|
|
169
184
|
data: encoded.data,
|
|
170
185
|
purpose,
|
|
@@ -176,7 +191,7 @@ export async function runEnsSetupRecordsTransaction(args: {
|
|
|
176
191
|
}
|
|
177
192
|
const result = await sendBrowserWalletTransaction({
|
|
178
193
|
chainId: 1,
|
|
179
|
-
expectedAccount:
|
|
194
|
+
expectedAccount: freshSetup.ownerAddress,
|
|
180
195
|
to: encoded.to,
|
|
181
196
|
data: encoded.data,
|
|
182
197
|
purpose,
|
|
@@ -187,6 +202,40 @@ export async function runEnsSetupRecordsTransaction(args: {
|
|
|
187
202
|
return { txHash: result.txHash }
|
|
188
203
|
}
|
|
189
204
|
|
|
205
|
+
async function refreshEnsSetupAgainstChain(setup: EnsSetupPlan, publicClient: PublicClient): Promise<EnsSetupPlan> {
|
|
206
|
+
if (setup.registryAction !== 'none' && !setup.recordDiffs.length && !setup.addressRecord.changed) {
|
|
207
|
+
return setup
|
|
208
|
+
}
|
|
209
|
+
const node = namehash(setup.fullName)
|
|
210
|
+
const keys = Array.from(new Set(setup.recordDiffs.map(diff => diff.key)))
|
|
211
|
+
let freshCurrent: AgentEnsRecordState = setup.currentRecords
|
|
212
|
+
if (keys.length > 0) {
|
|
213
|
+
try {
|
|
214
|
+
freshCurrent = await readEthagentTextRecords(setup.fullName, keys, { publicClient })
|
|
215
|
+
} catch {
|
|
216
|
+
freshCurrent = setup.currentRecords
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
let freshAddress = setup.addressRecord.current
|
|
220
|
+
try {
|
|
221
|
+
freshAddress = await readAddressRecord(publicClient, setup.resolverAddress, node)
|
|
222
|
+
} catch {
|
|
223
|
+
freshAddress = setup.addressRecord.current
|
|
224
|
+
}
|
|
225
|
+
const addressChanged = !freshAddress || getAddress(freshAddress).toLowerCase() !== getAddress(setup.addressRecord.next).toLowerCase()
|
|
226
|
+
const recordDiffs: AgentRecordDiff[] = diffRecords(freshCurrent, setup.nextRecords)
|
|
227
|
+
return {
|
|
228
|
+
...setup,
|
|
229
|
+
currentRecords: freshCurrent,
|
|
230
|
+
recordDiffs,
|
|
231
|
+
addressRecord: {
|
|
232
|
+
current: freshAddress,
|
|
233
|
+
next: setup.addressRecord.next,
|
|
234
|
+
changed: addressChanged,
|
|
235
|
+
},
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
190
239
|
export function createMainnetEnsPublicClient(): PublicClient {
|
|
191
240
|
return createErc8004PublicClient({
|
|
192
241
|
chainId: 1,
|
|
@@ -6,15 +6,9 @@ import {
|
|
|
6
6
|
type WalletChallengePurpose,
|
|
7
7
|
} from '../../continuity/envelope.js'
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
writePublicSkillsFile,
|
|
9
|
+
writeAgentCardFile,
|
|
11
10
|
} from '../../continuity/storage.js'
|
|
12
|
-
import {
|
|
13
|
-
createAgentCard,
|
|
14
|
-
defaultPublicSkillsProfile,
|
|
15
|
-
serializeAgentCard,
|
|
16
|
-
} from '../../continuity/publicSkills.js'
|
|
17
|
-
import { syncPublicSkillsManifest } from '../../continuity/skills/publicSkillsSync.js'
|
|
11
|
+
import { syncAgentCardManifest } from '../../continuity/skills/publicSkillsSync.js'
|
|
18
12
|
import { recordPublishedContinuitySnapshot } from '../../continuity/snapshots.js'
|
|
19
13
|
import { addToIpfs, DEFAULT_IPFS_API_URL, isPinataUploadUrl } from '../../storage/ipfs.js'
|
|
20
14
|
import {
|
|
@@ -63,15 +57,15 @@ import {
|
|
|
63
57
|
prepareOperatorProfileArtifacts,
|
|
64
58
|
} from './operatorSave.js'
|
|
65
59
|
|
|
66
|
-
type
|
|
60
|
+
type AgentCardMetadata = NonNullable<EthagentIdentity['agentCard']>
|
|
67
61
|
|
|
68
62
|
type PublicProfilePreparedTransaction = {
|
|
69
63
|
ownerAddress: Address
|
|
70
64
|
agentUri: string
|
|
71
65
|
metadataCid: string
|
|
72
|
-
|
|
66
|
+
agentCard: AgentCardMetadata
|
|
73
67
|
identity: EthagentIdentity
|
|
74
|
-
|
|
68
|
+
agentCardJson: string
|
|
75
69
|
}
|
|
76
70
|
|
|
77
71
|
export async function runPublicProfilePreflight(
|
|
@@ -151,20 +145,12 @@ async function runPublicProfileSigningInner(
|
|
|
151
145
|
includeLastBackedUpAt: false,
|
|
152
146
|
})
|
|
153
147
|
const nextIdentityForFiles: EthagentIdentity = { ...step.identity, state }
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
assertVerifiedPin(publicSkillsPin)
|
|
157
|
-
const agentCardPin = await addToIpfs(
|
|
158
|
-
DEFAULT_IPFS_API_URL,
|
|
159
|
-
serializeAgentCard(createAgentCard(defaultPublicSkillsProfile(nextIdentityForFiles))),
|
|
160
|
-
fetch,
|
|
161
|
-
{ pinataJwt: step.pinataJwt },
|
|
162
|
-
)
|
|
148
|
+
const agentCardJson = await syncAgentCardManifest(nextIdentityForFiles)
|
|
149
|
+
const agentCardPin = await addToIpfs(DEFAULT_IPFS_API_URL, agentCardJson, fetch, { pinataJwt: step.pinataJwt })
|
|
163
150
|
assertVerifiedPin(agentCardPin)
|
|
164
151
|
const updatedAt = new Date().toISOString()
|
|
165
|
-
const
|
|
166
|
-
cid:
|
|
167
|
-
agentCardCid: agentCardPin.cid,
|
|
152
|
+
const agentCard: AgentCardMetadata = {
|
|
153
|
+
cid: agentCardPin.cid,
|
|
168
154
|
updatedAt,
|
|
169
155
|
status: 'pinned',
|
|
170
156
|
}
|
|
@@ -181,8 +167,7 @@ async function runPublicProfileSigningInner(
|
|
|
181
167
|
}, {
|
|
182
168
|
backup: existingBackup,
|
|
183
169
|
publicDiscovery: {
|
|
184
|
-
|
|
185
|
-
agentCardCid: publicSkills.agentCardCid,
|
|
170
|
+
agentCardCid: agentCard.cid,
|
|
186
171
|
updatedAt,
|
|
187
172
|
},
|
|
188
173
|
registration: {
|
|
@@ -212,9 +197,9 @@ async function runPublicProfileSigningInner(
|
|
|
212
197
|
ownerAddress: snapshotOwner,
|
|
213
198
|
agentUri,
|
|
214
199
|
metadataCid,
|
|
215
|
-
|
|
200
|
+
agentCard,
|
|
216
201
|
identity: { ...step.identity, state },
|
|
217
|
-
|
|
202
|
+
agentCardJson,
|
|
218
203
|
},
|
|
219
204
|
}
|
|
220
205
|
},
|
|
@@ -231,9 +216,9 @@ async function runPublicProfileSigningInner(
|
|
|
231
216
|
identityRegistryAddress: step.registry.identityRegistryAddress,
|
|
232
217
|
agentUri: result.prepared.agentUri,
|
|
233
218
|
metadataCid: result.prepared.metadataCid,
|
|
234
|
-
|
|
219
|
+
agentCard: result.prepared.agentCard,
|
|
235
220
|
}
|
|
236
|
-
await
|
|
221
|
+
await writeAgentCardFile(nextIdentity, result.prepared.agentCardJson)
|
|
237
222
|
await markCurrentContinuityFilesPublished(nextIdentity)
|
|
238
223
|
const resolverSyncWarning = await syncVaultOperatorsAfterOwnerSave({
|
|
239
224
|
beforeIdentity: step.identity,
|
|
@@ -345,7 +330,7 @@ async function runOperatorWalletVaultPublicProfileSave(args: {
|
|
|
345
330
|
? { ...prepared.nextIdentity.backup, txHash: vaultTx.txHash }
|
|
346
331
|
: prepared.nextIdentity.backup,
|
|
347
332
|
}
|
|
348
|
-
await
|
|
333
|
+
await writeAgentCardFile(nextIdentity, prepared.agentCardJson)
|
|
349
334
|
await markCurrentContinuityFilesPublished(nextIdentity).catch(() => null)
|
|
350
335
|
await recordPublishedContinuitySnapshot({
|
|
351
336
|
identity: nextIdentity,
|
|
@@ -74,16 +74,14 @@ export function identitySummaryRows(
|
|
|
74
74
|
const tokenValue = identity?.agentId ? `#${identity.agentId}` : 'not created'
|
|
75
75
|
const chain = chainSummaryRow(config, identity)
|
|
76
76
|
const stateValue = backup?.cid ? shortCid(backup.cid) : 'not saved yet'
|
|
77
|
-
const
|
|
78
|
-
const cardValue = identity?.publicSkills?.agentCardCid ? shortCid(identity.publicSkills.agentCardCid) : 'not saved'
|
|
77
|
+
const cardValue = identity?.agentCard?.cid ? shortCid(identity.agentCard.cid) : 'not saved'
|
|
79
78
|
const iconValue = typeof identity?.state?.imageUrl === 'string' && identity.state.imageUrl.trim() ? 'attached' : 'not attached'
|
|
80
79
|
return [
|
|
81
80
|
{ label: 'owner wallet', value: ownerValue, tone: identity ? 'ok' : 'dim' },
|
|
82
81
|
{ label: 'token', value: tokenValue, tone: identity?.agentId ? 'ok' : 'dim' },
|
|
83
82
|
{ label: 'network', value: chain.value, tone: chain.tone },
|
|
84
83
|
{ label: 'state', value: stateValue, tone: backup ? 'ok' : 'dim' },
|
|
85
|
-
{ label: '
|
|
86
|
-
{ label: 'card', value: cardValue, tone: identity?.publicSkills?.agentCardCid ? 'ok' : 'dim' },
|
|
84
|
+
{ label: 'card', value: cardValue, tone: identity?.agentCard?.cid ? 'ok' : 'dim' },
|
|
87
85
|
{ label: 'icon', value: iconValue, tone: iconValue === 'attached' ? 'ok' : 'dim' },
|
|
88
86
|
]
|
|
89
87
|
}
|
|
@@ -10,14 +10,7 @@ import {
|
|
|
10
10
|
readContinuityFiles,
|
|
11
11
|
} from '../../continuity/storage.js'
|
|
12
12
|
import {
|
|
13
|
-
|
|
14
|
-
createAgentCard,
|
|
15
|
-
defaultPublicSkillsProfile,
|
|
16
|
-
serializeAgentCard,
|
|
17
|
-
} from '../../continuity/publicSkills.js'
|
|
18
|
-
import {
|
|
19
|
-
derivePublicSkillEntries,
|
|
20
|
-
syncPublicSkillsManifest,
|
|
13
|
+
syncAgentCardManifest,
|
|
21
14
|
} from '../../continuity/skills/publicSkillsSync.js'
|
|
22
15
|
import { addToIpfs, DEFAULT_IPFS_API_URL } from '../../storage/ipfs.js'
|
|
23
16
|
import {
|
|
@@ -40,12 +33,12 @@ import {
|
|
|
40
33
|
} from '../continuity/snapshot.js'
|
|
41
34
|
|
|
42
35
|
type BackupMetadata = NonNullable<EthagentIdentity['backup']>
|
|
43
|
-
type
|
|
36
|
+
type AgentCardMetadata = NonNullable<EthagentIdentity['agentCard']>
|
|
44
37
|
type WalletAccessContext = NonNullable<ReturnType<typeof walletRestoreAccessContext>>
|
|
45
38
|
|
|
46
39
|
export type OperatorProfileArtifacts = {
|
|
47
40
|
nextIdentity: EthagentIdentity
|
|
48
|
-
|
|
41
|
+
agentCardJson: string
|
|
49
42
|
agentUri: string
|
|
50
43
|
metadataCid: string
|
|
51
44
|
}
|
|
@@ -75,20 +68,8 @@ export async function prepareOperatorProfileArtifacts(args: {
|
|
|
75
68
|
})
|
|
76
69
|
const nextIdentityForFiles: EthagentIdentity = { ...step.identity, state }
|
|
77
70
|
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
assertVerifiedPin(publicSkillsPin)
|
|
81
|
-
const publicSkillEntries = await derivePublicSkillEntries(nextIdentityForFiles)
|
|
82
|
-
const augmentedPublicProfile = appendPublicSkillEntries(
|
|
83
|
-
defaultPublicSkillsProfile(nextIdentityForFiles),
|
|
84
|
-
publicSkillEntries,
|
|
85
|
-
)
|
|
86
|
-
const agentCardPin = await addToIpfs(
|
|
87
|
-
DEFAULT_IPFS_API_URL,
|
|
88
|
-
serializeAgentCard(createAgentCard(augmentedPublicProfile)),
|
|
89
|
-
fetch,
|
|
90
|
-
{ pinataJwt: step.pinataJwt },
|
|
91
|
-
)
|
|
71
|
+
const agentCardJson = await syncAgentCardManifest(nextIdentityForFiles)
|
|
72
|
+
const agentCardPin = await addToIpfs(DEFAULT_IPFS_API_URL, agentCardJson, fetch, { pinataJwt: step.pinataJwt })
|
|
92
73
|
assertVerifiedPin(agentCardPin)
|
|
93
74
|
|
|
94
75
|
const continuityFiles = await readContinuityFiles(nextIdentityForFiles)
|
|
@@ -108,9 +89,8 @@ export async function prepareOperatorProfileArtifacts(args: {
|
|
|
108
89
|
const statePin = await addToIpfs(DEFAULT_IPFS_API_URL, serializeContinuitySnapshotEnvelope(envelope), fetch, { pinataJwt: step.pinataJwt })
|
|
109
90
|
assertVerifiedPin(statePin)
|
|
110
91
|
|
|
111
|
-
const
|
|
112
|
-
cid:
|
|
113
|
-
agentCardCid: agentCardPin.cid,
|
|
92
|
+
const agentCard: AgentCardMetadata = {
|
|
93
|
+
cid: agentCardPin.cid,
|
|
114
94
|
updatedAt: envelope.createdAt,
|
|
115
95
|
status: 'pinned',
|
|
116
96
|
}
|
|
@@ -134,7 +114,7 @@ export async function prepareOperatorProfileArtifacts(args: {
|
|
|
134
114
|
...(uploadedImageUri ? { image: uploadedImageUri } : {}),
|
|
135
115
|
}, {
|
|
136
116
|
backup: { cid: statePin.cid, envelopeVersion: envelope.envelopeVersion, createdAt: envelope.createdAt },
|
|
137
|
-
publicDiscovery: {
|
|
117
|
+
publicDiscovery: { agentCardCid: agentCard.cid, updatedAt: agentCard.updatedAt },
|
|
138
118
|
registration: { chainId: step.registry.chainId, identityRegistryAddress: step.registry.identityRegistryAddress, agentId: step.identity.agentId },
|
|
139
119
|
ensName: nextEnsName,
|
|
140
120
|
operators: operatorsPointerFromState(state, nextEnsName),
|
|
@@ -149,14 +129,14 @@ export async function prepareOperatorProfileArtifacts(args: {
|
|
|
149
129
|
...step.identity,
|
|
150
130
|
state,
|
|
151
131
|
backup: { ...backup, metadataCid, agentUri },
|
|
152
|
-
|
|
132
|
+
agentCard,
|
|
153
133
|
agentUri,
|
|
154
134
|
metadataCid,
|
|
155
135
|
}
|
|
156
136
|
|
|
157
137
|
return {
|
|
158
138
|
nextIdentity,
|
|
159
|
-
|
|
139
|
+
agentCardJson,
|
|
160
140
|
agentUri,
|
|
161
141
|
metadataCid,
|
|
162
142
|
}
|