agentwallet-sdk 2.0.0 → 2.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 +88 -2
- package/dist/identity/erc8004.d.ts +538 -0
- package/dist/identity/erc8004.d.ts.map +1 -0
- package/dist/identity/erc8004.js +656 -0
- package/dist/identity/erc8004.js.map +1 -0
- package/dist/index.d.ts +308 -233
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/x402/__tests__/budget.test.d.ts +2 -0
- package/dist/x402/__tests__/budget.test.d.ts.map +1 -0
- package/dist/x402/__tests__/budget.test.js +114 -0
- package/dist/x402/__tests__/budget.test.js.map +1 -0
- package/dist/x402/__tests__/client.test.d.ts +2 -0
- package/dist/x402/__tests__/client.test.d.ts.map +1 -0
- package/dist/x402/__tests__/client.test.js +107 -0
- package/dist/x402/__tests__/client.test.js.map +1 -0
- package/dist/x402/budget.d.ts +52 -0
- package/dist/x402/budget.d.ts.map +1 -0
- package/dist/x402/budget.js +113 -0
- package/dist/x402/budget.js.map +1 -0
- package/dist/x402/client.d.ts +60 -0
- package/dist/x402/client.d.ts.map +1 -0
- package/dist/x402/client.js +205 -0
- package/dist/x402/client.js.map +1 -0
- package/dist/x402/index.d.ts +6 -0
- package/dist/x402/index.d.ts.map +1 -0
- package/dist/x402/index.js +6 -0
- package/dist/x402/index.js.map +1 -0
- package/dist/x402/middleware.d.ts +37 -0
- package/dist/x402/middleware.d.ts.map +1 -0
- package/dist/x402/middleware.js +65 -0
- package/dist/x402/middleware.js.map +1 -0
- package/dist/x402/types.d.ts +91 -0
- package/dist/x402/types.d.ts.map +1 -0
- package/dist/x402/types.js +9 -0
- package/dist/x402/types.js.map +1 -0
- package/package.json +14 -7
package/README.md
CHANGED
|
@@ -270,13 +270,99 @@ Server verifies payment → returns 200 + data
|
|
|
270
270
|
|
|
271
271
|
Your agent's keys never leave the non-custodial wallet. All payments respect on-chain spend limits set by the wallet owner.
|
|
272
272
|
|
|
273
|
+
## ERC-8004: On-Chain Agent Identity (v2.3.0)
|
|
274
|
+
|
|
275
|
+
Give your AI agent a portable, censorship-resistant identity on Ethereum via [ERC-8004 Trustless Agents](https://eips.ethereum.org/EIPS/eip-8004).
|
|
276
|
+
|
|
277
|
+
ERC-8004 provides three things:
|
|
278
|
+
- **Identity Registry** — ERC-721 NFT that resolves to an agent's registration file (name, description, services, capabilities)
|
|
279
|
+
- **Reputation Registry** — On-chain feedback signals (composable scoring)
|
|
280
|
+
- **Validation Registry** — Hooks for stakers, zkML verifiers, and TEE oracles
|
|
281
|
+
|
|
282
|
+
The SDK integrates the Identity Registry. Non-custodial — keys never leave the device.
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { ERC8004Client, buildDataURI, validateRegistrationFile } from '@agentwallet/sdk';
|
|
286
|
+
|
|
287
|
+
const identity = new ERC8004Client({
|
|
288
|
+
registryAddress: '0xYOUR_REGISTRY',
|
|
289
|
+
chain: 'base',
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Register your agent on-chain (auto-builds data URI if you don't pass one)
|
|
293
|
+
const { txHash, agentId } = await identity.registerAgent(
|
|
294
|
+
walletClient,
|
|
295
|
+
{
|
|
296
|
+
name: 'TradingAgent',
|
|
297
|
+
description: 'Autonomous DeFi trading agent with x402 support',
|
|
298
|
+
services: [
|
|
299
|
+
{ name: 'A2A', endpoint: 'https://agent.example/.well-known/agent-card.json', version: '0.3.0' },
|
|
300
|
+
{ name: 'MCP', endpoint: 'https://mcp.agent.example/', version: '2025-06-18' },
|
|
301
|
+
],
|
|
302
|
+
x402Support: true,
|
|
303
|
+
active: true,
|
|
304
|
+
supportedTrust: ['reputation'],
|
|
305
|
+
},
|
|
306
|
+
'ipfs://QmYourCID' // or omit to store fully on-chain as data URI
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
// Register the AI model powering this agent
|
|
310
|
+
await identity.setModelMetadata(walletClient, agentId!, {
|
|
311
|
+
model: 'claude-3-5-sonnet',
|
|
312
|
+
provider: 'anthropic',
|
|
313
|
+
version: '2.3.0',
|
|
314
|
+
capabilities: ['trading', 'research', 'payments'],
|
|
315
|
+
framework: 'custom',
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Resolve any agent's full identity
|
|
319
|
+
const agentData = await identity.lookupAgentIdentity(42n);
|
|
320
|
+
console.log(agentData.registrationFile?.name); // "TradingAgent"
|
|
321
|
+
console.log(agentData.modelMetadata?.model); // "claude-3-5-sonnet"
|
|
322
|
+
console.log(agentData.owner); // NFT owner address
|
|
323
|
+
|
|
324
|
+
// Validate a registration file before publishing
|
|
325
|
+
const errors = validateRegistrationFile(agentData.registrationFile!);
|
|
326
|
+
if (errors.length === 0) console.log('Valid ERC-8004 registration ✅');
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Agent Registry Identifier
|
|
330
|
+
|
|
331
|
+
Each agent is globally identified by a namespaced string:
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
eip155:8453:0xRegistryAddress ← namespace:chainId:contractAddress
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
import { formatAgentRegistry } from '@agentwallet/sdk';
|
|
339
|
+
const id = formatAgentRegistry(8453, '0xYOUR_REGISTRY');
|
|
340
|
+
// → "eip155:8453:0xYOUR_REGISTRY"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Fully On-Chain Storage (No IPFS Required)
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { buildDataURI, parseDataURI } from '@agentwallet/sdk';
|
|
347
|
+
|
|
348
|
+
// Encode registration file as a base64 data URI (embeds in the NFT)
|
|
349
|
+
const uri = buildDataURI({ name: 'MyAgent', description: '...', type: '...' });
|
|
350
|
+
// → "data:application/json;base64,eyJ0eXBlIjoi..."
|
|
351
|
+
|
|
352
|
+
// Decode it back
|
|
353
|
+
const file = parseDataURI(uri);
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
273
358
|
## How It Works
|
|
274
359
|
|
|
275
360
|
1. **Deploy** an AgentAccountV2 (ERC-6551 token-bound account tied to an NFT)
|
|
276
361
|
2. **Configure** spend policies per token — set per-tx and daily limits
|
|
277
362
|
3. **Register** your agent's hot wallet as an operator
|
|
278
|
-
4. **
|
|
279
|
-
5. **
|
|
363
|
+
4. **Register on-chain identity** via ERC-8004 (optional but recommended)
|
|
364
|
+
5. **Agent operates autonomously** — transactions within limits execute instantly
|
|
365
|
+
6. **Over-limit transactions queue** — owner gets notified, approves or cancels
|
|
280
366
|
|
|
281
367
|
All limits enforced on-chain. No off-chain dependencies. Fully auditable.
|
|
282
368
|
|
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ERC-8004: Trustless Agents — Identity Registry Integration
|
|
3
|
+
*
|
|
4
|
+
* Implements the Identity Registry component of ERC-8004, which provides every
|
|
5
|
+
* AI agent with a portable, censorship-resistant on-chain identifier using ERC-721
|
|
6
|
+
* with URIStorage extension.
|
|
7
|
+
*
|
|
8
|
+
* Spec: https://eips.ethereum.org/EIPS/eip-8004
|
|
9
|
+
* Status: DRAFT (August 2025). No official mainnet singleton deployed yet —
|
|
10
|
+
* registry address is configurable per deployment.
|
|
11
|
+
*
|
|
12
|
+
* Key Principle: Non-custodial. All signing happens locally via the caller's
|
|
13
|
+
* WalletClient. Keys never leave the device.
|
|
14
|
+
*/
|
|
15
|
+
import { type Address, type Hash, type Hex, type WalletClient } from 'viem';
|
|
16
|
+
/**
|
|
17
|
+
* Minimal ABI for the ERC-8004 Identity Registry.
|
|
18
|
+
* Extends ERC-721 with agent-specific registration functions.
|
|
19
|
+
*/
|
|
20
|
+
export declare const ERC8004IdentityRegistryAbi: readonly [{
|
|
21
|
+
readonly name: "register";
|
|
22
|
+
readonly type: "function";
|
|
23
|
+
readonly stateMutability: "nonpayable";
|
|
24
|
+
readonly inputs: readonly [{
|
|
25
|
+
readonly name: "agentURI";
|
|
26
|
+
readonly type: "string";
|
|
27
|
+
}];
|
|
28
|
+
readonly outputs: readonly [{
|
|
29
|
+
readonly name: "agentId";
|
|
30
|
+
readonly type: "uint256";
|
|
31
|
+
}];
|
|
32
|
+
}, {
|
|
33
|
+
readonly name: "registerWithMetadata";
|
|
34
|
+
readonly type: "function";
|
|
35
|
+
readonly stateMutability: "nonpayable";
|
|
36
|
+
readonly inputs: readonly [{
|
|
37
|
+
readonly name: "agentURI";
|
|
38
|
+
readonly type: "string";
|
|
39
|
+
}, {
|
|
40
|
+
readonly name: "metadata";
|
|
41
|
+
readonly type: "tuple[]";
|
|
42
|
+
readonly components: readonly [{
|
|
43
|
+
readonly name: "metadataKey";
|
|
44
|
+
readonly type: "string";
|
|
45
|
+
}, {
|
|
46
|
+
readonly name: "metadataValue";
|
|
47
|
+
readonly type: "bytes";
|
|
48
|
+
}];
|
|
49
|
+
}];
|
|
50
|
+
readonly outputs: readonly [{
|
|
51
|
+
readonly name: "agentId";
|
|
52
|
+
readonly type: "uint256";
|
|
53
|
+
}];
|
|
54
|
+
}, {
|
|
55
|
+
readonly name: "registerEmpty";
|
|
56
|
+
readonly type: "function";
|
|
57
|
+
readonly stateMutability: "nonpayable";
|
|
58
|
+
readonly inputs: readonly [];
|
|
59
|
+
readonly outputs: readonly [{
|
|
60
|
+
readonly name: "agentId";
|
|
61
|
+
readonly type: "uint256";
|
|
62
|
+
}];
|
|
63
|
+
}, {
|
|
64
|
+
readonly name: "setAgentURI";
|
|
65
|
+
readonly type: "function";
|
|
66
|
+
readonly stateMutability: "nonpayable";
|
|
67
|
+
readonly inputs: readonly [{
|
|
68
|
+
readonly name: "agentId";
|
|
69
|
+
readonly type: "uint256";
|
|
70
|
+
}, {
|
|
71
|
+
readonly name: "newURI";
|
|
72
|
+
readonly type: "string";
|
|
73
|
+
}];
|
|
74
|
+
readonly outputs: readonly [];
|
|
75
|
+
}, {
|
|
76
|
+
readonly name: "tokenURI";
|
|
77
|
+
readonly type: "function";
|
|
78
|
+
readonly stateMutability: "view";
|
|
79
|
+
readonly inputs: readonly [{
|
|
80
|
+
readonly name: "agentId";
|
|
81
|
+
readonly type: "uint256";
|
|
82
|
+
}];
|
|
83
|
+
readonly outputs: readonly [{
|
|
84
|
+
readonly name: "";
|
|
85
|
+
readonly type: "string";
|
|
86
|
+
}];
|
|
87
|
+
}, {
|
|
88
|
+
readonly name: "getMetadata";
|
|
89
|
+
readonly type: "function";
|
|
90
|
+
readonly stateMutability: "view";
|
|
91
|
+
readonly inputs: readonly [{
|
|
92
|
+
readonly name: "agentId";
|
|
93
|
+
readonly type: "uint256";
|
|
94
|
+
}, {
|
|
95
|
+
readonly name: "metadataKey";
|
|
96
|
+
readonly type: "string";
|
|
97
|
+
}];
|
|
98
|
+
readonly outputs: readonly [{
|
|
99
|
+
readonly name: "";
|
|
100
|
+
readonly type: "bytes";
|
|
101
|
+
}];
|
|
102
|
+
}, {
|
|
103
|
+
readonly name: "setMetadata";
|
|
104
|
+
readonly type: "function";
|
|
105
|
+
readonly stateMutability: "nonpayable";
|
|
106
|
+
readonly inputs: readonly [{
|
|
107
|
+
readonly name: "agentId";
|
|
108
|
+
readonly type: "uint256";
|
|
109
|
+
}, {
|
|
110
|
+
readonly name: "metadataKey";
|
|
111
|
+
readonly type: "string";
|
|
112
|
+
}, {
|
|
113
|
+
readonly name: "metadataValue";
|
|
114
|
+
readonly type: "bytes";
|
|
115
|
+
}];
|
|
116
|
+
readonly outputs: readonly [];
|
|
117
|
+
}, {
|
|
118
|
+
readonly name: "getAgentWallet";
|
|
119
|
+
readonly type: "function";
|
|
120
|
+
readonly stateMutability: "view";
|
|
121
|
+
readonly inputs: readonly [{
|
|
122
|
+
readonly name: "agentId";
|
|
123
|
+
readonly type: "uint256";
|
|
124
|
+
}];
|
|
125
|
+
readonly outputs: readonly [{
|
|
126
|
+
readonly name: "";
|
|
127
|
+
readonly type: "address";
|
|
128
|
+
}];
|
|
129
|
+
}, {
|
|
130
|
+
readonly name: "setAgentWallet";
|
|
131
|
+
readonly type: "function";
|
|
132
|
+
readonly stateMutability: "nonpayable";
|
|
133
|
+
readonly inputs: readonly [{
|
|
134
|
+
readonly name: "agentId";
|
|
135
|
+
readonly type: "uint256";
|
|
136
|
+
}, {
|
|
137
|
+
readonly name: "newWallet";
|
|
138
|
+
readonly type: "address";
|
|
139
|
+
}, {
|
|
140
|
+
readonly name: "deadline";
|
|
141
|
+
readonly type: "uint256";
|
|
142
|
+
}, {
|
|
143
|
+
readonly name: "signature";
|
|
144
|
+
readonly type: "bytes";
|
|
145
|
+
}];
|
|
146
|
+
readonly outputs: readonly [];
|
|
147
|
+
}, {
|
|
148
|
+
readonly name: "unsetAgentWallet";
|
|
149
|
+
readonly type: "function";
|
|
150
|
+
readonly stateMutability: "nonpayable";
|
|
151
|
+
readonly inputs: readonly [{
|
|
152
|
+
readonly name: "agentId";
|
|
153
|
+
readonly type: "uint256";
|
|
154
|
+
}];
|
|
155
|
+
readonly outputs: readonly [];
|
|
156
|
+
}, {
|
|
157
|
+
readonly name: "ownerOf";
|
|
158
|
+
readonly type: "function";
|
|
159
|
+
readonly stateMutability: "view";
|
|
160
|
+
readonly inputs: readonly [{
|
|
161
|
+
readonly name: "tokenId";
|
|
162
|
+
readonly type: "uint256";
|
|
163
|
+
}];
|
|
164
|
+
readonly outputs: readonly [{
|
|
165
|
+
readonly name: "";
|
|
166
|
+
readonly type: "address";
|
|
167
|
+
}];
|
|
168
|
+
}, {
|
|
169
|
+
readonly name: "Registered";
|
|
170
|
+
readonly type: "event";
|
|
171
|
+
readonly inputs: readonly [{
|
|
172
|
+
readonly name: "agentId";
|
|
173
|
+
readonly type: "uint256";
|
|
174
|
+
readonly indexed: true;
|
|
175
|
+
}, {
|
|
176
|
+
readonly name: "agentURI";
|
|
177
|
+
readonly type: "string";
|
|
178
|
+
readonly indexed: false;
|
|
179
|
+
}, {
|
|
180
|
+
readonly name: "owner";
|
|
181
|
+
readonly type: "address";
|
|
182
|
+
readonly indexed: true;
|
|
183
|
+
}];
|
|
184
|
+
}, {
|
|
185
|
+
readonly name: "URIUpdated";
|
|
186
|
+
readonly type: "event";
|
|
187
|
+
readonly inputs: readonly [{
|
|
188
|
+
readonly name: "agentId";
|
|
189
|
+
readonly type: "uint256";
|
|
190
|
+
readonly indexed: true;
|
|
191
|
+
}, {
|
|
192
|
+
readonly name: "newURI";
|
|
193
|
+
readonly type: "string";
|
|
194
|
+
readonly indexed: false;
|
|
195
|
+
}, {
|
|
196
|
+
readonly name: "updatedBy";
|
|
197
|
+
readonly type: "address";
|
|
198
|
+
readonly indexed: true;
|
|
199
|
+
}];
|
|
200
|
+
}, {
|
|
201
|
+
readonly name: "MetadataSet";
|
|
202
|
+
readonly type: "event";
|
|
203
|
+
readonly inputs: readonly [{
|
|
204
|
+
readonly name: "agentId";
|
|
205
|
+
readonly type: "uint256";
|
|
206
|
+
readonly indexed: true;
|
|
207
|
+
}, {
|
|
208
|
+
readonly name: "indexedMetadataKey";
|
|
209
|
+
readonly type: "string";
|
|
210
|
+
readonly indexed: true;
|
|
211
|
+
}, {
|
|
212
|
+
readonly name: "metadataKey";
|
|
213
|
+
readonly type: "string";
|
|
214
|
+
readonly indexed: false;
|
|
215
|
+
}, {
|
|
216
|
+
readonly name: "metadataValue";
|
|
217
|
+
readonly type: "bytes";
|
|
218
|
+
readonly indexed: false;
|
|
219
|
+
}];
|
|
220
|
+
}];
|
|
221
|
+
/**
|
|
222
|
+
* ERC-8004 agent service endpoint definition.
|
|
223
|
+
* Agents advertise how they can be reached (A2A, MCP, web, etc.).
|
|
224
|
+
*/
|
|
225
|
+
export interface AgentServiceEndpoint {
|
|
226
|
+
/** Service type: "A2A" | "MCP" | "web" | "OASF" | "ENS" | "DID" | "email" | string */
|
|
227
|
+
name: string;
|
|
228
|
+
/** Endpoint URI (https://, ipfs://, ENS name, DID, email) */
|
|
229
|
+
endpoint: string;
|
|
230
|
+
/** Protocol version (SHOULD be set, not mandatory per spec) */
|
|
231
|
+
version?: string;
|
|
232
|
+
/** OASF-specific: skill identifiers */
|
|
233
|
+
skills?: string[];
|
|
234
|
+
/** OASF-specific: domain identifiers */
|
|
235
|
+
domains?: string[];
|
|
236
|
+
}
|
|
237
|
+
/** Trust mechanisms the agent claims to support */
|
|
238
|
+
export type SupportedTrustMechanism = 'reputation' | 'crypto-economic' | 'tee-attestation' | 'zkml' | string;
|
|
239
|
+
/**
|
|
240
|
+
* ERC-8004 cross-chain registration reference.
|
|
241
|
+
* An agent may be registered on multiple chains.
|
|
242
|
+
*/
|
|
243
|
+
export interface AgentRegistrationRef {
|
|
244
|
+
agentId: number;
|
|
245
|
+
/** "{namespace}:{chainId}:{identityRegistry}" e.g. "eip155:1:0x742..." */
|
|
246
|
+
agentRegistry: string;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* ERC-8004 Agent Registration File (the off-chain JSON pointed to by agentURI).
|
|
250
|
+
* This is what clients parse to discover an agent's capabilities and endpoints.
|
|
251
|
+
*/
|
|
252
|
+
export interface AgentRegistrationFile {
|
|
253
|
+
/** MUST equal "https://eips.ethereum.org/EIPS/eip-8004#registration-v1" */
|
|
254
|
+
type: string;
|
|
255
|
+
/** Human-readable agent name */
|
|
256
|
+
name: string;
|
|
257
|
+
/** Description of what the agent does, pricing, interaction methods */
|
|
258
|
+
description: string;
|
|
259
|
+
/** Image URL for NFT marketplace display */
|
|
260
|
+
image?: string;
|
|
261
|
+
/** Communication endpoints */
|
|
262
|
+
services?: AgentServiceEndpoint[];
|
|
263
|
+
/** Whether the agent accepts x402 payments */
|
|
264
|
+
x402Support?: boolean;
|
|
265
|
+
/** Whether the agent is currently active */
|
|
266
|
+
active?: boolean;
|
|
267
|
+
/** Cross-chain identity references */
|
|
268
|
+
registrations?: AgentRegistrationRef[];
|
|
269
|
+
/** Trust models the agent participates in */
|
|
270
|
+
supportedTrust?: SupportedTrustMechanism[];
|
|
271
|
+
/** Arbitrary extension fields */
|
|
272
|
+
[key: string]: unknown;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Metadata about an AI model powering the agent.
|
|
276
|
+
* Stored on-chain as optional key/value pairs via getMetadata/setMetadata.
|
|
277
|
+
*/
|
|
278
|
+
export interface AgentModelMetadata {
|
|
279
|
+
/** Model identifier e.g. "claude-3-5-sonnet", "gpt-4o", "gemini-2.0-flash" */
|
|
280
|
+
model?: string;
|
|
281
|
+
/** Model provider e.g. "anthropic", "openai", "google" */
|
|
282
|
+
provider?: string;
|
|
283
|
+
/** Agent software version */
|
|
284
|
+
version?: string;
|
|
285
|
+
/** Primary capability categories e.g. ["coding", "research", "trading"] */
|
|
286
|
+
capabilities?: string[];
|
|
287
|
+
/** Framework used e.g. "langchain", "autogen", "custom" */
|
|
288
|
+
framework?: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Full resolved agent identity — combines on-chain registry data with
|
|
292
|
+
* the off-chain registration file.
|
|
293
|
+
*/
|
|
294
|
+
export interface AgentIdentity {
|
|
295
|
+
/** On-chain ERC-721 token ID */
|
|
296
|
+
agentId: bigint;
|
|
297
|
+
/** ERC-721 owner address (controls this agent's NFT) */
|
|
298
|
+
owner: Address;
|
|
299
|
+
/** URI pointing to the registration file */
|
|
300
|
+
agentURI: string;
|
|
301
|
+
/** Configured payment wallet (may be zero address if not set) */
|
|
302
|
+
agentWallet: Address;
|
|
303
|
+
/** Parsed registration file (null if URI not resolvable in this context) */
|
|
304
|
+
registrationFile: AgentRegistrationFile | null;
|
|
305
|
+
/** On-chain model metadata (if previously set) */
|
|
306
|
+
modelMetadata: AgentModelMetadata | null;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* On-chain metadata entry (mirrors the Solidity struct MetadataEntry).
|
|
310
|
+
*/
|
|
311
|
+
export interface MetadataEntry {
|
|
312
|
+
metadataKey: string;
|
|
313
|
+
metadataValue: Hex;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Configuration for the ERC-8004 Identity Registry client.
|
|
317
|
+
*/
|
|
318
|
+
export interface ERC8004ClientConfig {
|
|
319
|
+
/** Address of the deployed ERC-8004 Identity Registry contract */
|
|
320
|
+
registryAddress: Address;
|
|
321
|
+
/** Chain name (matches existing SDK chain strings) */
|
|
322
|
+
chain: 'base' | 'base-sepolia' | 'ethereum' | 'arbitrum' | 'polygon';
|
|
323
|
+
/** RPC URL (optional — uses chain default if omitted) */
|
|
324
|
+
rpcUrl?: string;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Result of a registerAgent call.
|
|
328
|
+
*/
|
|
329
|
+
export interface RegistrationResult {
|
|
330
|
+
/** Transaction hash of the register() call */
|
|
331
|
+
txHash: Hash;
|
|
332
|
+
/**
|
|
333
|
+
* The assigned agentId. Returned from the receipt's Registered event.
|
|
334
|
+
* Use lookupAgentsByOwner() to enumerate if needed before confirmation.
|
|
335
|
+
*/
|
|
336
|
+
agentId: bigint | null;
|
|
337
|
+
}
|
|
338
|
+
export declare const METADATA_KEYS: {
|
|
339
|
+
/** Reserved by spec — set via setAgentWallet(), not setMetadata() */
|
|
340
|
+
readonly AGENT_WALLET: "agentWallet";
|
|
341
|
+
/** Optional: AI model identifier */
|
|
342
|
+
readonly MODEL: "agentModel";
|
|
343
|
+
/** Optional: model provider */
|
|
344
|
+
readonly MODEL_PROVIDER: "agentModelProvider";
|
|
345
|
+
/** Optional: agent version string */
|
|
346
|
+
readonly VERSION: "agentVersion";
|
|
347
|
+
/** Optional: JSON-encoded capability tags */
|
|
348
|
+
readonly CAPABILITIES: "agentCapabilities";
|
|
349
|
+
/** Optional: agent framework name */
|
|
350
|
+
readonly FRAMEWORK: "agentFramework";
|
|
351
|
+
};
|
|
352
|
+
/** ERC-8004 registration file type string (MUST match this exactly) */
|
|
353
|
+
export declare const REGISTRATION_FILE_TYPE = "https://eips.ethereum.org/EIPS/eip-8004#registration-v1";
|
|
354
|
+
/**
|
|
355
|
+
* Known testnet deployments of ERC-8004 Identity Registry.
|
|
356
|
+
* Mainnet singleton not yet deployed (spec is DRAFT as of Feb 2026).
|
|
357
|
+
* Update these addresses once official deployments are announced.
|
|
358
|
+
*/
|
|
359
|
+
export declare const KNOWN_REGISTRY_ADDRESSES: Partial<Record<ERC8004ClientConfig['chain'], Address>>;
|
|
360
|
+
/**
|
|
361
|
+
* ERC-8004 Identity Registry client.
|
|
362
|
+
*
|
|
363
|
+
* Provides type-safe, non-custodial access to the ERC-8004 Identity Registry.
|
|
364
|
+
* All write operations require a WalletClient — keys never leave the caller's device.
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```typescript
|
|
368
|
+
* import { ERC8004Client } from '@agentwallet/sdk';
|
|
369
|
+
*
|
|
370
|
+
* const identity = new ERC8004Client({
|
|
371
|
+
* registryAddress: '0xYOUR_REGISTRY',
|
|
372
|
+
* chain: 'base',
|
|
373
|
+
* });
|
|
374
|
+
*
|
|
375
|
+
* // Register a new agent identity
|
|
376
|
+
* const { txHash, agentId } = await identity.registerAgent(
|
|
377
|
+
* walletClient,
|
|
378
|
+
* {
|
|
379
|
+
* name: 'MyTradingAgent',
|
|
380
|
+
* description: 'Autonomous DeFi trading agent',
|
|
381
|
+
* services: [{ name: 'A2A', endpoint: 'https://agent.example/.well-known/agent-card.json' }],
|
|
382
|
+
* x402Support: true,
|
|
383
|
+
* active: true,
|
|
384
|
+
* },
|
|
385
|
+
* 'ipfs://QmYourCID'
|
|
386
|
+
* );
|
|
387
|
+
*
|
|
388
|
+
* // Lookup an agent
|
|
389
|
+
* const agentIdentity = await identity.lookupAgentIdentity(walletClient.account!.address);
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
export declare class ERC8004Client {
|
|
393
|
+
private readonly publicClient;
|
|
394
|
+
private readonly config;
|
|
395
|
+
private readonly chain;
|
|
396
|
+
constructor(config: ERC8004ClientConfig);
|
|
397
|
+
/** @internal Get a viem contract instance for read operations */
|
|
398
|
+
private getReadContract;
|
|
399
|
+
/** @internal Get a viem contract instance for read+write operations */
|
|
400
|
+
private getWriteContract;
|
|
401
|
+
/**
|
|
402
|
+
* Register a new agent identity on-chain.
|
|
403
|
+
*
|
|
404
|
+
* Builds a spec-compliant registration file JSON and registers it via
|
|
405
|
+
* the Identity Registry. The URI can be:
|
|
406
|
+
* - An IPFS URI you've already pinned: "ipfs://QmYourCID"
|
|
407
|
+
* - A base64 data URI for fully on-chain storage (auto-generated if not provided)
|
|
408
|
+
* - An HTTPS URI pointing to a static JSON file
|
|
409
|
+
*
|
|
410
|
+
* Non-custodial: the walletClient signs the transaction locally.
|
|
411
|
+
*
|
|
412
|
+
* @param walletClient - WalletClient controlling the agent owner key
|
|
413
|
+
* @param metadata - Agent metadata to include in the registration file
|
|
414
|
+
* @param agentURI - URI for the registration file (auto-builds data URI if omitted)
|
|
415
|
+
* @param onChainMetadata - Optional extra on-chain key/value pairs
|
|
416
|
+
* @returns txHash and agentId (from Registered event)
|
|
417
|
+
*/
|
|
418
|
+
registerAgent(walletClient: WalletClient, metadata: Omit<AgentRegistrationFile, 'type'>, agentURI?: string, onChainMetadata?: Record<string, string>): Promise<RegistrationResult>;
|
|
419
|
+
/**
|
|
420
|
+
* Look up an agent's full identity by their on-chain token ID.
|
|
421
|
+
*
|
|
422
|
+
* Fetches: owner, URI, payment wallet, and attempts to parse the
|
|
423
|
+
* registration file. Also reads standard on-chain model metadata if present.
|
|
424
|
+
*
|
|
425
|
+
* @param agentId - The ERC-721 tokenId assigned during registration
|
|
426
|
+
*/
|
|
427
|
+
lookupAgentIdentity(agentId: bigint): Promise<AgentIdentity>;
|
|
428
|
+
/**
|
|
429
|
+
* Look up an agent's identity by their wallet/owner address.
|
|
430
|
+
* Scans the Registered event log to find the most recent agentId for this owner.
|
|
431
|
+
*
|
|
432
|
+
* @param ownerAddress - The agent owner's Ethereum address
|
|
433
|
+
* @param fromBlock - Start scanning from this block (default: 0)
|
|
434
|
+
*/
|
|
435
|
+
lookupAgentByOwner(ownerAddress: Address, fromBlock?: bigint): Promise<AgentIdentity | null>;
|
|
436
|
+
/**
|
|
437
|
+
* Update the agent's registration file URI.
|
|
438
|
+
* Only callable by the NFT owner or an approved operator.
|
|
439
|
+
*
|
|
440
|
+
* @param walletClient - Owner/operator WalletClient
|
|
441
|
+
* @param agentId - The agent's tokenId
|
|
442
|
+
* @param newURI - New URI pointing to updated registration file
|
|
443
|
+
*/
|
|
444
|
+
updateAgentURI(walletClient: WalletClient, agentId: bigint, newURI: string): Promise<Hash>;
|
|
445
|
+
/**
|
|
446
|
+
* Read a single on-chain metadata value for an agent.
|
|
447
|
+
*
|
|
448
|
+
* @param agentId - The agent's tokenId
|
|
449
|
+
* @param key - Metadata key (see METADATA_KEYS for standard keys)
|
|
450
|
+
* @returns Raw bytes value, or null if not set
|
|
451
|
+
*/
|
|
452
|
+
getOnChainMetadata(agentId: bigint, key: string): Promise<Hex | null>;
|
|
453
|
+
/**
|
|
454
|
+
* Write a single on-chain metadata value for an agent.
|
|
455
|
+
* Note: the reserved 'agentWallet' key cannot be set via this method.
|
|
456
|
+
*
|
|
457
|
+
* @param walletClient - Owner/operator WalletClient
|
|
458
|
+
* @param agentId - The agent's tokenId
|
|
459
|
+
* @param key - Metadata key
|
|
460
|
+
* @param value - UTF-8 string value (will be hex-encoded)
|
|
461
|
+
*/
|
|
462
|
+
setOnChainMetadata(walletClient: WalletClient, agentId: bigint, key: string, value: string): Promise<Hash>;
|
|
463
|
+
/**
|
|
464
|
+
* Write model metadata on-chain for an agent.
|
|
465
|
+
* Uses the standard METADATA_KEYS constants.
|
|
466
|
+
*
|
|
467
|
+
* @param walletClient - Owner/operator WalletClient
|
|
468
|
+
* @param agentId - The agent's tokenId
|
|
469
|
+
* @param model - Model metadata object
|
|
470
|
+
*/
|
|
471
|
+
setModelMetadata(walletClient: WalletClient, agentId: bigint, model: AgentModelMetadata): Promise<Hash[]>;
|
|
472
|
+
/**
|
|
473
|
+
* Read all standard model metadata for an agent.
|
|
474
|
+
* Returns null if no model metadata has been set.
|
|
475
|
+
*/
|
|
476
|
+
readModelMetadata(agentId: bigint): Promise<AgentModelMetadata | null>;
|
|
477
|
+
/**
|
|
478
|
+
* Get the configured payment wallet for an agent.
|
|
479
|
+
* Returns zero address if not set (payment defaults to NFT owner).
|
|
480
|
+
*
|
|
481
|
+
* @param agentId - The agent's tokenId
|
|
482
|
+
*/
|
|
483
|
+
getAgentWallet(agentId: bigint): Promise<Address>;
|
|
484
|
+
/**
|
|
485
|
+
* Set the payment wallet for an agent.
|
|
486
|
+
* Requires an EIP-712 signature from the new wallet to prove control.
|
|
487
|
+
* This prevents draining payments to an attacker-controlled address.
|
|
488
|
+
*
|
|
489
|
+
* Non-custodial: the signature is generated locally by the walletClient.
|
|
490
|
+
*
|
|
491
|
+
* @param walletClient - Owner WalletClient (must own the agent NFT)
|
|
492
|
+
* @param agentId - The agent's tokenId
|
|
493
|
+
* @param newWallet - New payment wallet address
|
|
494
|
+
* @param deadline - Signature deadline (Unix timestamp)
|
|
495
|
+
* @param signature - EIP-712 or ERC-1271 signature from newWallet proving control
|
|
496
|
+
*/
|
|
497
|
+
setAgentWallet(walletClient: WalletClient, agentId: bigint, newWallet: Address, deadline: bigint, signature: Hex): Promise<Hash>;
|
|
498
|
+
/**
|
|
499
|
+
* Clear the agent wallet (resets payment address to NFT owner).
|
|
500
|
+
*
|
|
501
|
+
* @param walletClient - Owner WalletClient
|
|
502
|
+
* @param agentId - The agent's tokenId
|
|
503
|
+
*/
|
|
504
|
+
unsetAgentWallet(walletClient: WalletClient, agentId: bigint): Promise<Hash>;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Build a base64 data URI from an agent registration file.
|
|
508
|
+
* Enables fully on-chain metadata storage without IPFS or HTTPS dependencies.
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* const uri = buildDataURI({ name: 'MyAgent', description: '...', ... });
|
|
512
|
+
* // → "data:application/json;base64,eyJ0..."
|
|
513
|
+
*/
|
|
514
|
+
export declare function buildDataURI(registrationFile: AgentRegistrationFile): string;
|
|
515
|
+
/**
|
|
516
|
+
* Parse a data URI or plain JSON string into an AgentRegistrationFile.
|
|
517
|
+
* For HTTPS/IPFS URIs, use resolveAgentURI() instead.
|
|
518
|
+
*/
|
|
519
|
+
export declare function parseDataURI(uri: string): AgentRegistrationFile;
|
|
520
|
+
/**
|
|
521
|
+
* Resolve an agentURI to its registration file.
|
|
522
|
+
* Supports: data URIs (inline), HTTPS (fetch), IPFS (not fetched — throws).
|
|
523
|
+
*/
|
|
524
|
+
export declare function resolveAgentURI(uri: string): Promise<AgentRegistrationFile>;
|
|
525
|
+
/**
|
|
526
|
+
* Validate an AgentRegistrationFile against ERC-8004 requirements.
|
|
527
|
+
* Returns an array of validation errors (empty = valid).
|
|
528
|
+
*/
|
|
529
|
+
export declare function validateRegistrationFile(file: AgentRegistrationFile): string[];
|
|
530
|
+
/**
|
|
531
|
+
* Format an agent registry identifier per ERC-8004 spec.
|
|
532
|
+
*
|
|
533
|
+
* @param chainId - Chain ID (e.g. 8453 for Base)
|
|
534
|
+
* @param registryAddress - Identity Registry contract address
|
|
535
|
+
* @returns "{namespace}:{chainId}:{identityRegistry}" e.g. "eip155:8453:0x742..."
|
|
536
|
+
*/
|
|
537
|
+
export declare function formatAgentRegistry(chainId: number, registryAddress: Address): string;
|
|
538
|
+
//# sourceMappingURL=erc8004.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erc8004.d.ts","sourceRoot":"","sources":["../../src/identity/erc8004.ts"],"names":[],"mappings":"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"}
|