@agentic-trust/agentic-trust-sdk 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +213 -0
  3. package/abis/BaseRegistrarImplementation.json +1013 -0
  4. package/abis/ETHRegistrarController.json +1004 -0
  5. package/abis/IdentityRegistry.json +1044 -0
  6. package/abis/NameWrapper.json +2026 -0
  7. package/abis/PublicResolver.json +1772 -0
  8. package/abis/ReputationRegistry.json +701 -0
  9. package/abis/ValidationRegistry.json +505 -0
  10. package/dist/AIAgentAssociationClient.d.ts +58 -0
  11. package/dist/AIAgentAssociationClient.d.ts.map +1 -0
  12. package/dist/AIAgentAssociationClient.js +100 -0
  13. package/dist/AIAgentAssociationClient.js.map +1 -0
  14. package/dist/AIAgentDiscoveryClient.d.ts +673 -0
  15. package/dist/AIAgentDiscoveryClient.d.ts.map +1 -0
  16. package/dist/AIAgentDiscoveryClient.js +3184 -0
  17. package/dist/AIAgentDiscoveryClient.js.map +1 -0
  18. package/dist/AIAgentENSClient.d.ts +149 -0
  19. package/dist/AIAgentENSClient.d.ts.map +1 -0
  20. package/dist/AIAgentENSClient.js +958 -0
  21. package/dist/AIAgentENSClient.js.map +1 -0
  22. package/dist/AIAgentIdentityClient.d.ts +159 -0
  23. package/dist/AIAgentIdentityClient.d.ts.map +1 -0
  24. package/dist/AIAgentIdentityClient.js +660 -0
  25. package/dist/AIAgentIdentityClient.js.map +1 -0
  26. package/dist/AIAgentL2ENSDurenClient.d.ts +120 -0
  27. package/dist/AIAgentL2ENSDurenClient.d.ts.map +1 -0
  28. package/dist/AIAgentL2ENSDurenClient.js +735 -0
  29. package/dist/AIAgentL2ENSDurenClient.js.map +1 -0
  30. package/dist/AIAgentL2ENSNamespaceClient.d.ts +58 -0
  31. package/dist/AIAgentL2ENSNamespaceClient.d.ts.map +1 -0
  32. package/dist/AIAgentL2ENSNamespaceClient.js +214 -0
  33. package/dist/AIAgentL2ENSNamespaceClient.js.map +1 -0
  34. package/dist/AIAgentReputationClient.d.ts +69 -0
  35. package/dist/AIAgentReputationClient.d.ts.map +1 -0
  36. package/dist/AIAgentReputationClient.js +203 -0
  37. package/dist/AIAgentReputationClient.js.map +1 -0
  38. package/dist/AIAgentValidationClient.d.ts +60 -0
  39. package/dist/AIAgentValidationClient.d.ts.map +1 -0
  40. package/dist/AIAgentValidationClient.js +123 -0
  41. package/dist/AIAgentValidationClient.js.map +1 -0
  42. package/dist/OrgIdentityClient.d.ts +27 -0
  43. package/dist/OrgIdentityClient.d.ts.map +1 -0
  44. package/dist/OrgIdentityClient.js +169 -0
  45. package/dist/OrgIdentityClient.js.map +1 -0
  46. package/dist/abis/BaseRegistrarImplementation.json +1013 -0
  47. package/dist/abis/ETHRegistrarController.json +1004 -0
  48. package/dist/abis/IdentityRegistry.json +1044 -0
  49. package/dist/abis/NameWrapper.json +2026 -0
  50. package/dist/abis/PublicResolver.json +1772 -0
  51. package/dist/abis/ReputationRegistry.json +701 -0
  52. package/dist/abis/ValidationRegistry.json +505 -0
  53. package/dist/index.d.ts +25 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +24 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/schema.d.ts +13 -0
  58. package/dist/schema.d.ts.map +1 -0
  59. package/dist/schema.js +696 -0
  60. package/dist/schema.js.map +1 -0
  61. package/dist/schemaKb.d.ts +12 -0
  62. package/dist/schemaKb.d.ts.map +1 -0
  63. package/dist/schemaKb.js +593 -0
  64. package/dist/schemaKb.js.map +1 -0
  65. package/dist/tsconfig.tsbuildinfo +1 -0
  66. package/dist/utils/did8004.d.ts +57 -0
  67. package/dist/utils/did8004.d.ts.map +1 -0
  68. package/dist/utils/did8004.js +127 -0
  69. package/dist/utils/did8004.js.map +1 -0
  70. package/dist/utils/didEns.d.ts +46 -0
  71. package/dist/utils/didEns.d.ts.map +1 -0
  72. package/dist/utils/didEns.js +107 -0
  73. package/dist/utils/didEns.js.map +1 -0
  74. package/dist/utils/didEthr.d.ts +40 -0
  75. package/dist/utils/didEthr.d.ts.map +1 -0
  76. package/dist/utils/didEthr.js +87 -0
  77. package/dist/utils/didEthr.js.map +1 -0
  78. package/package.json +79 -0
@@ -0,0 +1,660 @@
1
+ /**
2
+ * Agentic Trust SDK - Identity Client
3
+ * Extends the base ERC-8004 IdentityClient with AA-centric helpers.
4
+ *
5
+ * Uses AccountProvider (Ports & Adapters pattern) for chain I/O.
6
+ */
7
+ import { createPublicClient, http, hexToString, getAddress, } from 'viem';
8
+ import { sepolia, baseSepolia, optimismSepolia, linea, lineaSepolia } from 'viem/chains';
9
+ import { BaseIdentityClient, ViemAccountProvider, } from '@agentic-trust/8004-sdk';
10
+ import IdentityRegistryABI from './abis/IdentityRegistry.json';
11
+ function getChainById(chainId) {
12
+ switch (chainId) {
13
+ case 11155111: // ETH Sepolia
14
+ return sepolia;
15
+ case 84532: // Base Sepolia
16
+ return baseSepolia;
17
+ case 11155420: // Optimism Sepolia
18
+ return optimismSepolia;
19
+ case 59144: // Linea Mainnet
20
+ return linea;
21
+ case 59141: // Linea Sepolia
22
+ return lineaSepolia;
23
+ default:
24
+ console.warn(`Unknown chainId ${chainId}, defaulting to ETH Sepolia`);
25
+ return sepolia;
26
+ }
27
+ }
28
+ export class AIAgentIdentityClient extends BaseIdentityClient {
29
+ chain = null;
30
+ identityRegistryAddress;
31
+ publicClient = null;
32
+ walletClient = null;
33
+ // accountProvider is protected in BaseIdentityClient, so we need to keep it accessible
34
+ accountProvider;
35
+ constructor(options) {
36
+ let accountProvider;
37
+ let chain = null;
38
+ let publicClient = null;
39
+ let walletClient = null;
40
+ let identityRegistryAddress;
41
+ if ('accountProvider' in options) {
42
+ // Option 1: Use provided AccountProvider (recommended)
43
+ accountProvider = options.accountProvider;
44
+ identityRegistryAddress = options.identityRegistryAddress;
45
+ // Try to extract publicClient from AccountProvider if it's a ViemAccountProvider
46
+ const viemProvider = accountProvider;
47
+ if (viemProvider.publicClient) {
48
+ publicClient = viemProvider.publicClient;
49
+ }
50
+ if (viemProvider.walletClient) {
51
+ walletClient = viemProvider.walletClient;
52
+ }
53
+ if (viemProvider.chainConfig?.chain) {
54
+ chain = viemProvider.chainConfig.chain;
55
+ }
56
+ }
57
+ else if ('publicClient' in options) {
58
+ // Option 2: Use viem clients directly (simplest, native viem)
59
+ publicClient = options.publicClient;
60
+ walletClient = options.walletClient ?? null;
61
+ identityRegistryAddress = options.identityRegistryAddress;
62
+ // Create ChainConfig
63
+ const chainConfig = options.chainConfig || {
64
+ id: publicClient.chain?.id || 11155111,
65
+ rpcUrl: publicClient.transport?.url || '',
66
+ name: publicClient.chain?.name || 'Unknown',
67
+ chain: publicClient.chain || undefined,
68
+ };
69
+ // Create ViemAccountProvider from the clients
70
+ accountProvider = new ViemAccountProvider({
71
+ publicClient,
72
+ walletClient: walletClient ?? null,
73
+ account: walletClient?.account,
74
+ chainConfig,
75
+ });
76
+ }
77
+ else {
78
+ // Option 3: Legacy pattern - create from chainId/rpcUrl
79
+ chain = getChainById(options.chainId);
80
+ // @ts-ignore - viem version compatibility issue
81
+ publicClient = createPublicClient({ chain, transport: http(options.rpcUrl) });
82
+ walletClient = options.walletClient ?? null;
83
+ // Create ChainConfig
84
+ const chainConfig = {
85
+ id: options.chainId,
86
+ rpcUrl: options.rpcUrl,
87
+ name: chain.name,
88
+ chain: chain,
89
+ bundlerUrl: options.bundlerUrl,
90
+ paymasterUrl: options.paymasterUrl,
91
+ };
92
+ // Create ViemAccountProvider
93
+ accountProvider = new ViemAccountProvider({
94
+ publicClient,
95
+ walletClient: walletClient ?? null,
96
+ account: options.account || walletClient?.account,
97
+ chainConfig,
98
+ });
99
+ identityRegistryAddress = options.identityRegistryAddress;
100
+ }
101
+ // Pass accountProvider to BaseIdentityClient
102
+ super(accountProvider, identityRegistryAddress);
103
+ this.chain = chain;
104
+ this.publicClient = publicClient;
105
+ this.walletClient = walletClient;
106
+ this.identityRegistryAddress = identityRegistryAddress;
107
+ this.accountProvider = accountProvider;
108
+ }
109
+ /**
110
+ * Get metadata using AccountProvider
111
+ */
112
+ async getMetadata(agentId, key) {
113
+ const bytes = await this.accountProvider.call({
114
+ to: this.identityRegistryAddress,
115
+ abi: IdentityRegistryABI,
116
+ functionName: 'getMetadata',
117
+ args: [agentId, key],
118
+ });
119
+ // Most keys store UTF-8 encoded bytes, but some (like reserved agentWallet) store raw bytes.
120
+ // Avoid lossy UTF-8 decoding by falling back to raw hex if decoding fails.
121
+ const raw = String(bytes || '').trim();
122
+ if (!raw || raw === '0x')
123
+ return '';
124
+ // Common case: reserved agentWallet is stored as abi.encodePacked(address) => 20 bytes.
125
+ // If the raw bytes look like a 20-byte hex, return it as a checksummed address string.
126
+ if (key === 'agentWallet' && /^0x[0-9a-fA-F]{40}$/.test(raw)) {
127
+ return getAddress(raw);
128
+ }
129
+ try {
130
+ return hexToString(raw);
131
+ }
132
+ catch {
133
+ return raw;
134
+ }
135
+ }
136
+ /**
137
+ * Get the verified agent wallet address (IdentityRegistry.getAgentWallet).
138
+ * This is the canonical way to read the "agentWallet" value as an address.
139
+ */
140
+ async getAgentWallet(agentId) {
141
+ const wallet = await this.accountProvider.call({
142
+ to: this.identityRegistryAddress,
143
+ abi: IdentityRegistryABI,
144
+ functionName: 'getAgentWallet',
145
+ args: [agentId],
146
+ });
147
+ return getAddress(wallet);
148
+ }
149
+ /**
150
+ * Get all available metadata from the Agent NFT by trying a comprehensive list of common keys.
151
+ * Returns a record of all metadata key-value pairs that exist on-chain.
152
+ *
153
+ * Processes requests in batches to avoid rate limiting.
154
+ *
155
+ * IMPORTANT: This method makes many on-chain RPC calls and should ONLY be used
156
+ * for detailed agent views (via loadAgentDetail). It should NOT be called for
157
+ * list queries - use GraphQL/discovery data instead.
158
+ */
159
+ async getAllMetadata(agentId) {
160
+ // Comprehensive list of common metadata keys to check
161
+ const METADATA_KEYS = [
162
+ // Standard ERC-8004 fields
163
+ 'agentName',
164
+ 'agentAccount',
165
+ 'description',
166
+ 'image',
167
+ 'external_url',
168
+ 'version',
169
+ 'type',
170
+ 'name',
171
+ 'url',
172
+ 'website',
173
+ 'email',
174
+ 'twitter',
175
+ 'github',
176
+ 'discord',
177
+ 'telegram',
178
+ 'metadata',
179
+ 'attributes',
180
+ 'createdAt',
181
+ 'updatedAt',
182
+ // Additional common fields
183
+ 'tags',
184
+ 'glbUrl',
185
+ 'glbCid',
186
+ 'glbFileName',
187
+ 'glbSource',
188
+ 'agentWallet',
189
+ 'capabilities',
190
+ 'role',
191
+ 'rating',
192
+ 'pricing',
193
+ 'pka',
194
+ 'uri',
195
+ 'endpoints',
196
+ 'supportedTrust',
197
+ 'registrations',
198
+ 'agentUrl',
199
+ 'contractAddress',
200
+ 'did',
201
+ 'didIdentity',
202
+ 'didAccount',
203
+ 'didName',
204
+ 'active',
205
+ 'x402support',
206
+ 'mcp',
207
+ 'a2aEndpoint',
208
+ 'mcpEndpoint',
209
+ 'ensEndpoint',
210
+ 'agentAccountEndpoint',
211
+ // Agent registration metadata
212
+ 'registeredBy',
213
+ 'registryNamespace',
214
+ 'uaid',
215
+ ];
216
+ const metadata = {};
217
+ // Fast path: use viem multicall when available to reduce RPC round-trips.
218
+ // This turns "N keys => N RPC calls" into ~1 RPC call (provider-dependent).
219
+ if (this.publicClient && typeof this.publicClient.multicall === 'function') {
220
+ try {
221
+ const contracts = METADATA_KEYS.map((key) => ({
222
+ address: this.identityRegistryAddress,
223
+ abi: IdentityRegistryABI,
224
+ functionName: 'getMetadata',
225
+ args: [agentId, key],
226
+ }));
227
+ const results = await this.publicClient.multicall({
228
+ contracts,
229
+ allowFailure: true,
230
+ });
231
+ for (let i = 0; i < METADATA_KEYS.length; i += 1) {
232
+ const key = METADATA_KEYS[i];
233
+ const r = results?.[i];
234
+ const ok = r && (r.status === 'success' || r.status === undefined);
235
+ const raw = ok ? String(r.result ?? '').trim() : '';
236
+ if (!raw || raw === '0x')
237
+ continue;
238
+ // Same decoding behavior as getMetadata()
239
+ if (key === 'agentWallet' && /^0x[0-9a-fA-F]{40}$/.test(raw)) {
240
+ metadata[key] = getAddress(raw);
241
+ continue;
242
+ }
243
+ try {
244
+ const decoded = hexToString(raw);
245
+ if (decoded && decoded.trim().length > 0) {
246
+ metadata[key] = decoded;
247
+ }
248
+ else {
249
+ metadata[key] = raw;
250
+ }
251
+ }
252
+ catch {
253
+ metadata[key] = raw;
254
+ }
255
+ }
256
+ return metadata;
257
+ }
258
+ catch {
259
+ // Fall back to per-key calls below
260
+ }
261
+ }
262
+ // Process requests in batches to avoid rate limiting
263
+ // Batch size: 5 requests at a time
264
+ // Delay between batches: 200ms
265
+ const BATCH_SIZE = 5;
266
+ const BATCH_DELAY_MS = 200;
267
+ for (let i = 0; i < METADATA_KEYS.length; i += BATCH_SIZE) {
268
+ const batch = METADATA_KEYS.slice(i, i + BATCH_SIZE);
269
+ // Process batch in parallel
270
+ const batchPromises = batch.map(async (key) => {
271
+ try {
272
+ const value = await this.getMetadata(agentId, key);
273
+ if (value && value.trim().length > 0) {
274
+ return { key, value };
275
+ }
276
+ return null;
277
+ }
278
+ catch (error) {
279
+ // Check if it's a rate limit error (429)
280
+ const errorMessage = error instanceof Error ? error.message : String(error);
281
+ if (errorMessage.includes('429') || errorMessage.includes('Too Many Requests')) {
282
+ // For rate limit errors, wait longer before retrying
283
+ await new Promise(resolve => setTimeout(resolve, 1000));
284
+ try {
285
+ const value = await this.getMetadata(agentId, key);
286
+ if (value && value.trim().length > 0) {
287
+ return { key, value };
288
+ }
289
+ }
290
+ catch (retryError) {
291
+ // Silently skip on retry failure
292
+ }
293
+ }
294
+ // Silently skip if metadata key doesn't exist or fails
295
+ return null;
296
+ }
297
+ });
298
+ const batchResults = await Promise.all(batchPromises);
299
+ // Collect successful results from this batch
300
+ for (const result of batchResults) {
301
+ if (result) {
302
+ metadata[result.key] = result.value;
303
+ }
304
+ }
305
+ // Delay before next batch (except for the last batch)
306
+ if (i + BATCH_SIZE < METADATA_KEYS.length) {
307
+ await new Promise(resolve => setTimeout(resolve, BATCH_DELAY_MS));
308
+ }
309
+ }
310
+ return metadata;
311
+ }
312
+ /**
313
+ * Encode function call data using AccountProvider
314
+ */
315
+ async encodeFunctionData(abi, functionName, args) {
316
+ return await this.accountProvider.encodeFunctionData({
317
+ abi,
318
+ functionName,
319
+ args,
320
+ });
321
+ }
322
+ /**
323
+ * Legacy method - delegates to encodeFunctionData
324
+ * @deprecated Use encodeFunctionData instead
325
+ */
326
+ encodeCall(abi, functionName, args) {
327
+ // This is a synchronous method, but encodeFunctionData is async
328
+ // For backward compatibility, we'll use ethers for now
329
+ // TODO: Consider making this async or removing it
330
+ const { ethers } = require('ethers');
331
+ const iface = new ethers.Interface(abi);
332
+ return iface.encodeFunctionData(functionName, args);
333
+ }
334
+ /**
335
+ * Encode register calldata without sending (for bundler/AA - like EAS SDK pattern)
336
+ * This override exists in the Agentic Trust SDK to keep AA helpers here.
337
+ */
338
+ async encodeRegisterWithMetadata(tokenUri, metadata = []) {
339
+ // Format metadata: convert string values to hex strings (Viem expects hex for bytes)
340
+ const metadataFormatted = metadata.map(m => {
341
+ // Use stringToBytes from base class (via inheritance)
342
+ const bytes = this.stringToBytes(m.value);
343
+ // Convert to hex string (Viem requires hex strings, not Uint8Array)
344
+ const hexString = this.bytesToHex(bytes);
345
+ return {
346
+ // Updated ABI uses struct fields: { metadataKey, metadataValue }
347
+ metadataKey: m.key,
348
+ metadataValue: hexString,
349
+ };
350
+ });
351
+ // Use AccountProvider's encodeFunctionData
352
+ return await this.accountProvider.encodeFunctionData({
353
+ abi: IdentityRegistryABI,
354
+ functionName: 'register',
355
+ args: [tokenUri, metadataFormatted],
356
+ });
357
+ }
358
+ async encodeRegister(name, agentAccount, tokenUri) {
359
+ console.info("name: ", name);
360
+ console.info("agentAccount: ", agentAccount);
361
+ return await this.encodeRegisterWithMetadata(tokenUri, [{ key: 'agentName', value: name }, { key: 'agentAccount', value: agentAccount }]);
362
+ }
363
+ async prepareRegisterCalls(name, agentAccount, tokenUri, additionalMetadata) {
364
+ const metadata = [
365
+ { key: 'agentName', value: name },
366
+ { key: 'agentAccount', value: agentAccount },
367
+ ...(additionalMetadata || []),
368
+ ];
369
+ const data = await this.encodeRegisterWithMetadata(tokenUri, metadata);
370
+ const calls = [];
371
+ calls.push({
372
+ to: this.identityRegistryAddress,
373
+ data: data
374
+ });
375
+ return { calls };
376
+ }
377
+ async encodeSetRegistrationUri(agentId, uri) {
378
+ const data = await this.accountProvider.encodeFunctionData({
379
+ abi: IdentityRegistryABI,
380
+ // Updated ABI name is setAgentURI (capital URI)
381
+ functionName: 'setAgentURI',
382
+ args: [agentId, uri],
383
+ });
384
+ return data;
385
+ }
386
+ async prepareSetRegistrationUriCalls(agentId, uri) {
387
+ const calls = [];
388
+ const data = await this.encodeSetRegistrationUri(agentId, uri);
389
+ calls.push({
390
+ to: this.identityRegistryAddress,
391
+ data: data
392
+ });
393
+ return { calls };
394
+ }
395
+ /**
396
+ * Encode `setAgentWallet` calldata without sending.
397
+ *
398
+ * IdentityRegistry ABI:
399
+ * setAgentWallet(uint256 agentId, address newWallet, uint256 deadline, bytes signature)
400
+ */
401
+ async encodeSetAgentWallet(agentId, newWallet, deadline, signature) {
402
+ const data = await this.accountProvider.encodeFunctionData({
403
+ abi: IdentityRegistryABI,
404
+ functionName: 'setAgentWallet',
405
+ args: [agentId, newWallet, deadline, signature],
406
+ });
407
+ return data;
408
+ }
409
+ async prepareSetAgentWalletCalls(agentId, newWallet, deadline, signature) {
410
+ const calls = [];
411
+ const data = await this.encodeSetAgentWallet(agentId, newWallet, deadline, signature);
412
+ calls.push({
413
+ to: this.identityRegistryAddress,
414
+ data,
415
+ });
416
+ return { calls };
417
+ }
418
+ /**
419
+ * Prepare a complete transaction for client-side signing (similar to prepareCall for bundlers)
420
+ * All Ethereum logic (encoding, gas estimation, nonce) is handled server-side
421
+ * Client only needs to sign and send with MetaMask
422
+ * @param tokenUri - IPFS token URI for the agent registration
423
+ * @param metadata - Metadata entries for the agent
424
+ * @param fromAddress - Address that will sign the transaction (only address needed, no client)
425
+ * @returns Prepared transaction object ready for client-side signing
426
+ */
427
+ async prepareRegisterTransaction(tokenUri, metadata, fromAddress) {
428
+ // Encode the transaction data
429
+ const encodedData = await this.encodeRegisterWithMetadata(tokenUri, metadata);
430
+ // Get chain ID using AccountProvider
431
+ const chainId = await this.accountProvider.chainId();
432
+ // Initialize gas estimation variables
433
+ let gasEstimate;
434
+ let gasPrice;
435
+ let maxFeePerGas;
436
+ let maxPriorityFeePerGas;
437
+ let nonce;
438
+ try {
439
+ // Get current block data to check for EIP-1559 support
440
+ const blockData = await this.accountProvider.getBlock('latest');
441
+ // Prefer EIP-1559 (maxFeePerGas/maxPriorityFeePerGas) if available
442
+ // Otherwise fall back to legacy gasPrice
443
+ if (blockData && 'baseFeePerGas' in blockData && blockData.baseFeePerGas) {
444
+ // EIP-1559: Use maxFeePerGas and maxPriorityFeePerGas
445
+ // Set a reasonable priority fee (1-2 gwei typically)
446
+ // maxFeePerGas should be baseFeePerGas + maxPriorityFeePerGas + buffer
447
+ maxPriorityFeePerGas = 1000000000n; // 1 gwei as priority fee
448
+ maxFeePerGas = (blockData.baseFeePerGas * 2n) + maxPriorityFeePerGas; // 2x base + priority (buffer for safety)
449
+ }
450
+ else {
451
+ // Legacy: Use gasPrice
452
+ gasPrice = await this.accountProvider.getGasPrice();
453
+ }
454
+ // Estimate gas using AccountProvider
455
+ gasEstimate = await this.accountProvider.estimateGas({
456
+ account: fromAddress,
457
+ to: this.identityRegistryAddress,
458
+ data: encodedData,
459
+ });
460
+ // Get nonce using AccountProvider
461
+ nonce = await this.accountProvider.getTransactionCount(fromAddress, 'pending');
462
+ }
463
+ catch (error) {
464
+ console.warn('Could not estimate gas or get transaction parameters:', error);
465
+ // Continue without gas estimates - client can estimate
466
+ }
467
+ // Build transaction object - return hex strings for all bigint values (Viem accepts hex strings directly)
468
+ // This format can be used directly with Viem's sendTransaction without client-side conversion
469
+ const txParams = {
470
+ to: this.identityRegistryAddress,
471
+ data: encodedData,
472
+ value: '0x0', // Hex string for value
473
+ gas: gasEstimate ? `0x${gasEstimate.toString(16)}` : undefined,
474
+ nonce,
475
+ chainId,
476
+ };
477
+ // Include EIP-1559 fields if available, otherwise legacy gasPrice
478
+ // All as hex strings for direct Viem compatibility
479
+ if (maxFeePerGas && maxPriorityFeePerGas) {
480
+ txParams.maxFeePerGas = `0x${maxFeePerGas.toString(16)}`;
481
+ txParams.maxPriorityFeePerGas = `0x${maxPriorityFeePerGas.toString(16)}`;
482
+ }
483
+ else if (gasPrice) {
484
+ txParams.gasPrice = `0x${gasPrice.toString(16)}`;
485
+ }
486
+ return txParams;
487
+ }
488
+ async isValidAgentAccount(agentAccount) {
489
+ try {
490
+ // Use AccountProvider's ReadClient interface - check if address has code
491
+ // We can use a simple call to check if it's a contract
492
+ // For now, we'll use publicClient if available, otherwise return null
493
+ if (this.publicClient) {
494
+ const code = await this.publicClient.getBytecode({ address: agentAccount });
495
+ return code ? true : false;
496
+ }
497
+ // AccountProvider doesn't expose getBytecode directly, so we check via isContractSigner
498
+ // This is a workaround - ideally AccountProvider would expose getBytecode
499
+ return null;
500
+ }
501
+ catch {
502
+ return null;
503
+ }
504
+ }
505
+ /**
506
+ * Extract agentId from a user operation/transaction receipt
507
+ * Public in this SDK to support AA flows explicitly.
508
+ */
509
+ extractAgentIdFromReceiptPublic(receipt) {
510
+ // Look for parsed events first
511
+ if (receipt?.events) {
512
+ const registeredEvent = receipt.events.find((e) => e.name === 'Registered');
513
+ if (registeredEvent?.args) {
514
+ const val = registeredEvent.args.agentId ?? registeredEvent.args[0];
515
+ if (val !== undefined)
516
+ return BigInt(val);
517
+ }
518
+ const transferEvent = receipt.events.find((e) => e.name === 'Transfer' && (e.args.from === '0x0000000000000000000000000000000000000000' || e.args.from === 0 || e.args.from === 0n));
519
+ if (transferEvent?.args) {
520
+ const val = transferEvent.args.tokenId ?? transferEvent.args[2];
521
+ if (val !== undefined)
522
+ return BigInt(val);
523
+ }
524
+ }
525
+ // Fallback: raw logs array
526
+ if (receipt?.logs && Array.isArray(receipt.logs)) {
527
+ for (const log of receipt.logs) {
528
+ // Transfer(address,address,uint256)
529
+ if (log.topics && log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef') {
530
+ const from = log.topics[1];
531
+ if (from === '0x0000000000000000000000000000000000000000000000000000000000000000') {
532
+ const tokenId = BigInt(log.topics[3] || log.data);
533
+ return tokenId;
534
+ }
535
+ }
536
+ }
537
+ }
538
+ throw new Error('Could not extract agentId from transaction receipt - Registered or Transfer event not found');
539
+ }
540
+ /**
541
+ * Get the owner (EOA) of an account address
542
+ *
543
+ * @param accountAddress - The account address (smart account or contract)
544
+ * @returns The owner address (EOA) or null if not found or error
545
+ */
546
+ async getAccountOwner(accountAddress) {
547
+ try {
548
+ const owner = await this.accountProvider.call({
549
+ to: accountAddress,
550
+ abi: [{ name: 'owner', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'address' }] }],
551
+ functionName: 'owner',
552
+ args: [],
553
+ });
554
+ return owner;
555
+ }
556
+ catch {
557
+ return null;
558
+ }
559
+ }
560
+ /**
561
+ * @deprecated Use getAccountOwner instead
562
+ */
563
+ async getAgentEoaByAgentAccount(agentAccount) {
564
+ return this.getAccountOwner(agentAccount);
565
+ }
566
+ /**
567
+ * Get agentName from on-chain metadata (string value)
568
+ */
569
+ async getAgentName(agentId) {
570
+ try {
571
+ const name = await this.getMetadata(agentId, 'agentName');
572
+ if (typeof name === 'string') {
573
+ const trimmed = name.trim();
574
+ return trimmed.length > 0 ? trimmed : null;
575
+ }
576
+ return name ? String(name) : null;
577
+ }
578
+ catch (error) {
579
+ console.info("++++++++++++++++++++++++ getAgentName: error", error);
580
+ return null;
581
+ }
582
+ }
583
+ /**
584
+ * Get agentAccount address from on-chain metadata.
585
+ * Supports CAIP-10 format like "eip155:11155111:0x..." or raw 0x address.
586
+ */
587
+ async getAgentAccount(agentId) {
588
+ try {
589
+ const value = await this.getMetadata(agentId, 'agentAccount');
590
+ if (!value)
591
+ return null;
592
+ if (typeof value === 'string') {
593
+ const v = value.trim();
594
+ if (v.startsWith('eip155:')) {
595
+ const parts = v.split(':');
596
+ const addr = parts[2];
597
+ if (addr && /^0x[a-fA-F0-9]{40}$/.test(addr))
598
+ return addr;
599
+ }
600
+ if (/^0x[a-fA-F0-9]{40}$/.test(v))
601
+ return v;
602
+ }
603
+ return null;
604
+ }
605
+ catch {
606
+ return null;
607
+ }
608
+ }
609
+ /**
610
+ * Get agentCategory from on-chain metadata (string value)
611
+ * Returns one of the standard agent category types from the OAS ecosystem.
612
+ */
613
+ async getAgentCategory(agentId) {
614
+ try {
615
+ const category = await this.getMetadata(agentId, 'agentCategory');
616
+ if (typeof category === 'string') {
617
+ const trimmed = category.trim();
618
+ return trimmed.length > 0 ? trimmed : null;
619
+ }
620
+ return category ? String(category) : null;
621
+ }
622
+ catch (error) {
623
+ console.info("++++++++++++++++++++++++ getAgentCategory: error", error);
624
+ return null;
625
+ }
626
+ }
627
+ /**
628
+ * Keep compatibility: delegate to receipt extractor.
629
+ */
630
+ extractAgentIdFromLogs(receipt) {
631
+ return this.extractAgentIdFromReceiptPublic(receipt);
632
+ }
633
+ /**
634
+ * Get the approved operator address for an agent NFT token
635
+ * Returns the address approved to operate on the token, or null if no operator is set
636
+ *
637
+ * @param agentId - The agent ID (token ID)
638
+ * @returns The approved operator address, or null if no operator is set (zero address)
639
+ */
640
+ async getNFTOperator(agentId) {
641
+ try {
642
+ const operatorAddress = await this.accountProvider.call({
643
+ to: this.identityRegistryAddress,
644
+ abi: IdentityRegistryABI,
645
+ functionName: 'getApproved',
646
+ args: [agentId],
647
+ });
648
+ // Check if operator is set (not zero address)
649
+ if (operatorAddress && operatorAddress !== '0x0000000000000000000000000000000000000000') {
650
+ return operatorAddress;
651
+ }
652
+ return null;
653
+ }
654
+ catch (error) {
655
+ console.error('Failed to get NFT operator:', error);
656
+ return null;
657
+ }
658
+ }
659
+ }
660
+ //# sourceMappingURL=AIAgentIdentityClient.js.map