@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,735 @@
1
+ import { createPublicClient, http, encodeFunctionData, zeroAddress, namehash } from 'viem';
2
+ import { AIAgentENSClient } from './AIAgentENSClient';
3
+ export class AIAgentL2ENSDurenClient extends AIAgentENSClient {
4
+ constructor(chain, rpcUrl, adapter, ensRegistryAddress, ensResolverAddress, identityRegistryAddress) {
5
+ super(chain, rpcUrl, adapter, ensRegistryAddress, ensResolverAddress, identityRegistryAddress);
6
+ }
7
+ /** Chain ID for Linea Sepolia (registry uses createSubnode(baseNode, label, owner, [])). */
8
+ static CHAIN_ID_LINEA_SEPOLIA = 59141;
9
+ /** Chain ID for Linea Mainnet (Durin L2Registry acts as registry + resolver). */
10
+ static CHAIN_ID_LINEA_MAINNET = 59144;
11
+ /**
12
+ * L2Registrar address per chain. Base Sepolia uses a separate L2Registrar contract;
13
+ * Linea Sepolia uses the registry's createSubnode(bytes32,string,address,bytes[]) (no separate registrar).
14
+ */
15
+ getL2RegistrarAddress() {
16
+ const chainId = this.chain?.id;
17
+ if (chainId === 84532)
18
+ return '0x68CAd072571E8bea1DA9e5C071367Aa6ddC8F37F';
19
+ return null;
20
+ }
21
+ /** True when this chain uses registry.createSubnode for subdomain registration (e.g. Linea Sepolia). */
22
+ usesRegistryCreateSubnode() {
23
+ const id = this.chain?.id;
24
+ return (id === AIAgentL2ENSDurenClient.CHAIN_ID_LINEA_SEPOLIA ||
25
+ id === AIAgentL2ENSDurenClient.CHAIN_ID_LINEA_MAINNET);
26
+ }
27
+ getEffectiveRpcUrl() {
28
+ const rpc = this.rpcUrl;
29
+ if (typeof rpc === 'string' && rpc.trim())
30
+ return rpc.trim();
31
+ const chain = this.chain;
32
+ const first = chain?.rpcUrls?.default?.http?.[0];
33
+ return typeof first === 'string' ? first : undefined;
34
+ }
35
+ hasValidResolver() {
36
+ const addr = this.getEnsResolverAddress();
37
+ return typeof addr === 'string' && addr.length > 0 && addr !== zeroAddress;
38
+ }
39
+ /**
40
+ * Guard for preparing metadata calls (setAddr/setText/etc).
41
+ *
42
+ * Historically Linea Sepolia used a registry that was not a resolver, so we rejected resolver===registry.
43
+ * If the deployed contract implements both registry+resolver interfaces at the same address, allow it.
44
+ */
45
+ hasValidResolverForSetInfo() {
46
+ if (!this.hasValidResolver())
47
+ return false;
48
+ return true;
49
+ }
50
+ /**
51
+ * Override to ensure L2 client always returns true for isL2()
52
+ */
53
+ isL2() {
54
+ return true; // This is always an L2 client
55
+ }
56
+ /**
57
+ * Override to ensure L2 client always returns false for isL1()
58
+ */
59
+ isL1() {
60
+ return false; // This is never an L1 client
61
+ }
62
+ /**
63
+ * Override to ensure L2 client always returns 'L2'
64
+ */
65
+ getChainType() {
66
+ return 'L2';
67
+ }
68
+ async getAgentUrlByName(name) {
69
+ try {
70
+ if (!this.hasValidResolver())
71
+ return null;
72
+ const rpcUrl = this.getEffectiveRpcUrl();
73
+ if (!rpcUrl)
74
+ return null;
75
+ const node = namehash(name);
76
+ const resolverAddress = this.getEnsResolverAddress();
77
+ const resolverAbi = [
78
+ {
79
+ "inputs": [
80
+ {
81
+ "internalType": "bytes32",
82
+ "name": "node",
83
+ "type": "bytes32"
84
+ },
85
+ {
86
+ "internalType": "string",
87
+ "name": "key",
88
+ "type": "string"
89
+ }
90
+ ],
91
+ "name": "text",
92
+ "outputs": [
93
+ {
94
+ "internalType": "string",
95
+ "name": "",
96
+ "type": "string"
97
+ }
98
+ ],
99
+ "stateMutability": "view",
100
+ "type": "function"
101
+ }
102
+ ];
103
+ const publicClient = createPublicClient({
104
+ chain: this.chain,
105
+ transport: http(rpcUrl),
106
+ });
107
+ const url = await publicClient.readContract({
108
+ address: resolverAddress,
109
+ abi: resolverAbi,
110
+ functionName: 'text',
111
+ args: [node, 'url'],
112
+ });
113
+ // Return null if URL is empty
114
+ if (!url || url.trim() === '') {
115
+ return null;
116
+ }
117
+ return url;
118
+ }
119
+ catch (error) {
120
+ console.error('Error resolving URL for name:', name, error);
121
+ return null;
122
+ }
123
+ }
124
+ async getAgentAccountByName(name) {
125
+ try {
126
+ const node = namehash(name);
127
+ const rpcUrl = this.getEffectiveRpcUrl();
128
+ if (!rpcUrl)
129
+ return null;
130
+ const publicClient = createPublicClient({
131
+ chain: this.chain,
132
+ transport: http(rpcUrl),
133
+ });
134
+ const ensRegistryAddress = this.getEnsRegistryAddress();
135
+ const ensRegistryAbi = [
136
+ { inputs: [{ internalType: 'bytes32', name: 'node', type: 'bytes32' }], name: 'owner', outputs: [{ internalType: 'address', name: '', type: 'address' }], stateMutability: 'view', type: 'function' },
137
+ ];
138
+ const owner = await publicClient.readContract({
139
+ address: ensRegistryAddress,
140
+ abi: ensRegistryAbi,
141
+ functionName: 'owner',
142
+ args: [node],
143
+ });
144
+ if (!owner || owner === zeroAddress)
145
+ return null;
146
+ if (!this.hasValidResolver())
147
+ return null;
148
+ const resolverAddress = this.getEnsResolverAddress();
149
+ // ENS Resolver ABI for addr function
150
+ const resolverAbi = [
151
+ {
152
+ "inputs": [
153
+ {
154
+ "internalType": "bytes32",
155
+ "name": "node",
156
+ "type": "bytes32"
157
+ }
158
+ ],
159
+ "name": "addr",
160
+ "outputs": [
161
+ {
162
+ "internalType": "address",
163
+ "name": "",
164
+ "type": "address"
165
+ }
166
+ ],
167
+ "stateMutability": "view",
168
+ "type": "function"
169
+ }
170
+ ];
171
+ /*
172
+ // TEST: Check resolver status
173
+ console.info("********************* TEST: Checking resolver for name:", name);
174
+
175
+ // Check if resolver is set for this node
176
+ const registryResolverAbi = [
177
+ {
178
+ "inputs": [
179
+ {
180
+ "internalType": "bytes32",
181
+ "name": "node",
182
+ "type": "bytes32"
183
+ }
184
+ ],
185
+ "name": "resolver",
186
+ "outputs": [
187
+ {
188
+ "internalType": "address",
189
+ "name": "",
190
+ "type": "address"
191
+ }
192
+ ],
193
+ "stateMutability": "view",
194
+ "type": "function"
195
+ }
196
+ ] as const;
197
+
198
+ try {
199
+ const resolver = await // @ts-ignore - viem version compatibility issue
200
+ publicClient.readContract({
201
+ address: ensRegistryAddress,
202
+ abi: registryResolverAbi,
203
+ functionName: 'resolver',
204
+ args: [node]
205
+ });
206
+
207
+ console.info("********************* TEST: Resolver for", name, ":", resolver);
208
+
209
+ if (resolver && resolver !== '0x0000000000000000000000000000000000000000') {
210
+ console.info("********************* TEST: RESOLVER EXISTS - Name has resolver:", resolver);
211
+ } else {
212
+ console.info("********************* TEST: NO RESOLVER - Name has no resolver set");
213
+ }
214
+ } catch (resolverError) {
215
+ console.error("********************* TEST: Error checking resolver:", resolverError);
216
+ }
217
+ */
218
+ // Call the resolver directly to get address
219
+ const addressResolverAbi = [
220
+ {
221
+ "inputs": [
222
+ {
223
+ "internalType": "bytes32",
224
+ "name": "node",
225
+ "type": "bytes32"
226
+ }
227
+ ],
228
+ "name": "addr",
229
+ "outputs": [
230
+ {
231
+ "internalType": "address",
232
+ "name": "",
233
+ "type": "address"
234
+ }
235
+ ],
236
+ "stateMutability": "view",
237
+ "type": "function"
238
+ }
239
+ ];
240
+ const address = await publicClient.readContract({
241
+ address: resolverAddress,
242
+ abi: addressResolverAbi,
243
+ functionName: 'addr',
244
+ args: [node],
245
+ });
246
+ // Return null if address is zero address
247
+ if (!address || address === '0x0000000000000000000000000000000000000000') {
248
+ return null;
249
+ }
250
+ return address;
251
+ }
252
+ catch (error) {
253
+ console.error('Error resolving address for name:', name, error);
254
+ return null;
255
+ }
256
+ }
257
+ /**
258
+ * Note: getAgentEoaByAgentAccount is not a method of AIAgentENSClient
259
+ * This method is actually in AIAgentIdentityClient, so we don't need to override it here.
260
+ * The ownership detection logic is handled in the UI layer (AddAgentModal.tsx)
261
+ */
262
+ /**
263
+ * Override hasAgentNameOwner to use L2Registrar available() function
264
+ */
265
+ async hasAgentNameOwner(orgName, agentName) {
266
+ console.info("AIAgentL2ENSDurenClient.hasAgentNameOwner");
267
+ const clean = (s) => (s || '').trim().toLowerCase();
268
+ const parent = clean(orgName);
269
+ const label = clean(agentName).replace(/\s+/g, '-');
270
+ console.info("AIAgentL2ENSDurenClient.hasAgentNameOwner: label", label);
271
+ console.info("AIAgentL2ENSDurenClient.hasAgentNameOwner: parent", parent);
272
+ const fullSubname = `${label}.${parent}`;
273
+ console.info("AIAgentL2ENSDurenClient.hasAgentNameOwner: fullSubname", fullSubname);
274
+ const l2RegistrarAddress = this.getL2RegistrarAddress();
275
+ if (!l2RegistrarAddress) {
276
+ // No L2Registrar on this chain (e.g. Linea Sepolia); fall back to ENS registry owner(node)
277
+ try {
278
+ const rpcUrl = this.getEffectiveRpcUrl();
279
+ if (!rpcUrl)
280
+ return false;
281
+ const node = namehash(fullSubname);
282
+ const publicClient = createPublicClient({
283
+ chain: this.chain,
284
+ transport: http(rpcUrl),
285
+ });
286
+ const owner = await publicClient.readContract({
287
+ address: this.getEnsRegistryAddress(),
288
+ abi: [{ inputs: [{ name: 'node', type: 'bytes32' }], name: 'owner', outputs: [{ type: 'address' }], stateMutability: 'view', type: 'function' }],
289
+ functionName: 'owner',
290
+ args: [node],
291
+ });
292
+ const hasOwner = owner && owner !== zeroAddress;
293
+ console.info(`AIAgentL2ENSDurenClient.hasAgentNameOwner: "${fullSubname}" (registry) ${hasOwner ? 'HAS owner' : 'has NO owner'}`);
294
+ return hasOwner;
295
+ }
296
+ catch (err) {
297
+ console.error('Error checking agent name owner via registry:', err);
298
+ return false;
299
+ }
300
+ }
301
+ const l2RegistrarAbi = [
302
+ {
303
+ "inputs": [
304
+ {
305
+ "internalType": "string",
306
+ "name": "label",
307
+ "type": "string"
308
+ }
309
+ ],
310
+ "name": "available",
311
+ "outputs": [
312
+ {
313
+ "internalType": "bool",
314
+ "name": "available",
315
+ "type": "bool"
316
+ }
317
+ ],
318
+ "stateMutability": "view",
319
+ "type": "function"
320
+ }
321
+ ];
322
+ const publicClient = // @ts-ignore - viem version compatibility issue
323
+ createPublicClient({
324
+ chain: this.chain,
325
+ transport: http(this.rpcUrl)
326
+ });
327
+ try {
328
+ // Call registrar.available(label) - returns true if available, false if taken
329
+ const isAvailable = await // @ts-ignore - viem version compatibility issue
330
+ publicClient.readContract({
331
+ address: l2RegistrarAddress,
332
+ abi: l2RegistrarAbi,
333
+ functionName: 'available',
334
+ args: [label]
335
+ });
336
+ // If not available, then it has an owner
337
+ const hasOwner = !isAvailable;
338
+ console.info(`AIAgentL2ENSDurenClient.hasAgentNameOwner: "${fullSubname}" (label: "${label}") ${hasOwner ? 'HAS owner' : 'has NO owner'} (available: ${isAvailable})`);
339
+ return hasOwner;
340
+ }
341
+ catch (error) {
342
+ console.error('Error checking agent name owner via registrar:', error);
343
+ return false;
344
+ }
345
+ }
346
+ async prepareAddAgentNameToOrgCalls(params) {
347
+ console.log("AIAgentL2ENSDurenClient.prepareAddAgentNameToOrgCalls");
348
+ console.log("orgName: ", params.orgName);
349
+ console.log("agentName: ", params.agentName);
350
+ console.log("agentAddress: ", params.agentAddress);
351
+ console.log("agentUrl: ", params.agentUrl);
352
+ const clean = (s) => (s || '').trim().toLowerCase();
353
+ const parent = clean(params.orgName) + ".eth";
354
+ const label = clean(params.agentName).replace(/\s+/g, '-');
355
+ const fullSubname = `${label}.${parent}`;
356
+ const agentAddress = params.agentAddress;
357
+ const agentUrl = params.agentUrl;
358
+ const chainName = this.chain.name.toLowerCase().replace(/\s+/g, '-');
359
+ console.info("parent: ", parent);
360
+ console.info("label: ", label);
361
+ console.info("fullSubname: ", fullSubname);
362
+ console.info("agentAddress: ", agentAddress);
363
+ console.info("chainName: ", chainName);
364
+ console.info("agentUrl: ", agentUrl);
365
+ const calls = [];
366
+ try {
367
+ // Step 1: Register the subdomain with L2Registrar
368
+ const registrationCall = await this.registerSubdomain(label, agentAddress);
369
+ // Add registration call
370
+ calls.push(...registrationCall.calls);
371
+ /*
372
+
373
+ // Step 2: Set address records for the subdomain
374
+ const chainId = (this as any).chain.id;
375
+
376
+ // Set Base Sepolia address record (coinType 2147568164)
377
+ if (chainId === 84532) { // Base Sepolia
378
+ const baseAddrCall = await this.setResolverAddrRecordDirect(
379
+ fullSubname,
380
+ 2147568164, // Base Sepolia coin type
381
+ agentAddress
382
+ );
383
+ calls.push(baseAddrCall);
384
+ }
385
+
386
+
387
+ // Set Ethereum address record (coinType 60) for cross-chain compatibility
388
+ const ethAddrCall = await this.setResolverAddrRecordDirect(
389
+ fullSubname,
390
+ 60, // Ethereum coin type
391
+ agentAddress
392
+ );
393
+ calls.push(ethAddrCall);
394
+
395
+
396
+ // Step 3: Set resolver records for the subdomain
397
+ const textRecords = [
398
+ { key: 'name', value: label },
399
+ { key: 'url', value: agentUrl },
400
+ { key: 'description', value: `Agent: ${label}` },
401
+ { key: 'chain', value: chainName },
402
+ { key: 'agent-account', value: agentAddress },
403
+ ];
404
+
405
+ for (const record of textRecords) {
406
+ const recordCall = await this.setResolverTextRecordDirect(
407
+ fullSubname,
408
+ record.key,
409
+ record.value,
410
+ );
411
+ calls.push(recordCall);
412
+ }
413
+
414
+
415
+
416
+
417
+ console.info("Generated calls count: ", calls.length);
418
+ console.info("Calls: ", calls);
419
+
420
+ */
421
+ }
422
+ catch (error) {
423
+ console.error("Error preparing agent name calls:", error);
424
+ throw error;
425
+ }
426
+ return { calls };
427
+ }
428
+ async prepareAddAgentInfoCalls(params) {
429
+ console.log("AIAgentL2ENSDurenClient.prepareAddAgentNameToOrgCalls");
430
+ console.log("orgName: ", params.orgName);
431
+ console.log("agentName: ", params.agentName);
432
+ console.log("agentAddress: ", params.agentAddress);
433
+ console.log("agentUrl: ", params.agentUrl);
434
+ const clean = (s) => (s || '').trim().toLowerCase();
435
+ const parent = clean(params.orgName) + ".eth";
436
+ const label = clean(params.agentName).replace(/\s+/g, '-');
437
+ const fullSubname = `${label}.${parent}`;
438
+ const agentAddress = params.agentAddress;
439
+ const agentUrl = params.agentUrl;
440
+ const chainName = this.chain.name.toLowerCase().replace(/\s+/g, '-');
441
+ console.info("parent: ", parent);
442
+ console.info("label: ", label);
443
+ console.info("fullSubname: ", fullSubname);
444
+ console.info("agentAddress: ", agentAddress);
445
+ console.info("chainName: ", chainName);
446
+ console.info("agentUrl: ", agentUrl);
447
+ const calls = [];
448
+ try {
449
+ // Step 2: Set address records for the subdomain
450
+ const chainId = this.chain.id;
451
+ // Set Base Sepolia address record (coinType 2147568164)
452
+ if (chainId === 84532) { // Base Sepolia
453
+ const baseAddrCall = await this.setResolverAddrRecordDirect(fullSubname, 2147568164, // Base Sepolia coin type
454
+ agentAddress);
455
+ calls.push(baseAddrCall);
456
+ }
457
+ /*
458
+ // Set Ethereum address record (coinType 60) for cross-chain compatibility
459
+ const ethAddrCall = await this.setResolverAddrRecordDirect(
460
+ fullSubname,
461
+ 60, // Ethereum coin type
462
+ agentAddress
463
+ );
464
+ calls.push(ethAddrCall);
465
+ */
466
+ // Step 3: Set resolver records for the subdomain
467
+ const textRecords = [
468
+ //{ key: 'name', value: label },
469
+ { key: 'url', value: agentUrl },
470
+ //{ key: 'description', value: `Agent: ${label}` },
471
+ //{ key: 'chain', value: chainName },
472
+ //{ key: 'agent-account', value: agentAddress },
473
+ ];
474
+ // Add description if provided
475
+ if (params.agentDescription && params.agentDescription.trim() !== '') {
476
+ textRecords.push({ key: 'description', value: params.agentDescription.trim() });
477
+ }
478
+ for (const record of textRecords) {
479
+ const recordCall = await this.setResolverTextRecordDirect(fullSubname, record.key, record.value);
480
+ calls.push(recordCall);
481
+ }
482
+ console.info("Generated calls count: ", calls.length);
483
+ console.info("Calls: ", calls);
484
+ }
485
+ catch (error) {
486
+ console.error("Error preparing agent name calls:", error);
487
+ throw error;
488
+ }
489
+ return { calls };
490
+ }
491
+ async prepareSetNameUriCalls(name, uri) {
492
+ const calls = [];
493
+ return { calls };
494
+ }
495
+ /**
496
+ * Register subdomain using L2Registrar contract (Base Sepolia specific)
497
+ */
498
+ async registerSubdomain(subdomain, owner) {
499
+ console.log("AIAgentL2ENSDurenClient.registerSubdomain", { subdomain, owner });
500
+ const calls = [];
501
+ // Linea Sepolia: registry has baseNode() and createSubnode(bytes32,string,address,bytes[])
502
+ if (this.usesRegistryCreateSubnode()) {
503
+ const rpcUrl = this.getEffectiveRpcUrl();
504
+ if (!rpcUrl)
505
+ return { calls };
506
+ const registryAddress = this.getEnsRegistryAddress();
507
+ const publicClient = createPublicClient({
508
+ chain: this.chain,
509
+ transport: http(rpcUrl),
510
+ });
511
+ const baseNodeAbi = [{ inputs: [], name: 'baseNode', outputs: [{ type: 'bytes32' }], stateMutability: 'view', type: 'function' }];
512
+ const baseNode = await publicClient.readContract({
513
+ address: registryAddress,
514
+ abi: baseNodeAbi,
515
+ functionName: 'baseNode',
516
+ });
517
+ const createSubnodeAbi = [
518
+ {
519
+ inputs: [
520
+ { internalType: 'bytes32', name: 'baseNode', type: 'bytes32' },
521
+ { internalType: 'string', name: 'label', type: 'string' },
522
+ { internalType: 'address', name: 'owner', type: 'address' },
523
+ { internalType: 'bytes[]', name: 'data', type: 'bytes[]' },
524
+ ],
525
+ name: 'createSubnode',
526
+ outputs: [],
527
+ stateMutability: 'nonpayable',
528
+ type: 'function',
529
+ },
530
+ ];
531
+ const data = encodeFunctionData({
532
+ abi: createSubnodeAbi,
533
+ functionName: 'createSubnode',
534
+ args: [baseNode, subdomain, owner, []],
535
+ });
536
+ calls.push({ to: registryAddress, data, value: 0n });
537
+ return { calls };
538
+ }
539
+ const l2RegistrarAddress = this.getL2RegistrarAddress();
540
+ if (!l2RegistrarAddress) {
541
+ return { calls };
542
+ }
543
+ // Base Sepolia: separate L2Registrar with register(string, address)
544
+ const l2RegistrarAbi = [
545
+ {
546
+ inputs: [
547
+ { internalType: 'string', name: 'name', type: 'string' },
548
+ { internalType: 'address', name: 'owner', type: 'address' },
549
+ ],
550
+ name: 'register',
551
+ outputs: [],
552
+ stateMutability: 'nonpayable',
553
+ type: 'function',
554
+ },
555
+ ];
556
+ const registerData = encodeFunctionData({
557
+ abi: l2RegistrarAbi,
558
+ functionName: 'register',
559
+ args: [subdomain, owner],
560
+ });
561
+ calls.push({ to: l2RegistrarAddress, data: registerData, value: 0n });
562
+ return { calls };
563
+ }
564
+ /**
565
+ * Direct chain call for setting resolver records
566
+ */
567
+ async setResolverTextRecordDirect(name, key, value) {
568
+ console.log("AIAgentL2ENSDurenClient.setResolverTextRecordDirect");
569
+ console.log("name:", name);
570
+ console.log("key:", key);
571
+ console.log("value:", value);
572
+ const resolverAddress = this.getEnsResolverAddress();
573
+ // ENS Resolver ABI for setText
574
+ const resolverAbi = [
575
+ {
576
+ "inputs": [
577
+ {
578
+ "internalType": "bytes32",
579
+ "name": "node",
580
+ "type": "bytes32"
581
+ },
582
+ {
583
+ "internalType": "string",
584
+ "name": "key",
585
+ "type": "string"
586
+ },
587
+ {
588
+ "internalType": "string",
589
+ "name": "value",
590
+ "type": "string"
591
+ }
592
+ ],
593
+ "name": "setText",
594
+ "outputs": [],
595
+ "stateMutability": "nonpayable",
596
+ "type": "function"
597
+ }
598
+ ];
599
+ // Calculate namehash for the subdomain
600
+ const node = namehash(name);
601
+ // Encode the setText function call
602
+ const data = encodeFunctionData({
603
+ abi: resolverAbi,
604
+ functionName: 'setText',
605
+ args: [node, key, value]
606
+ });
607
+ return {
608
+ to: resolverAddress,
609
+ data
610
+ };
611
+ }
612
+ /**
613
+ * Override for Linea Sepolia (59141): registry does not implement resolver(node).
614
+ * When no resolver is configured return empty; otherwise use configured resolver address and skip registry lookups.
615
+ */
616
+ async prepareSetAgentNameInfoCalls(params) {
617
+ if (this.usesRegistryCreateSubnode()) {
618
+ const chainId = this.chain?.id;
619
+ // Linea Mainnet Durin L2Registry: registry is also the resolver.
620
+ // Linea Sepolia: requires a separately configured resolver; otherwise skip.
621
+ if (chainId === AIAgentL2ENSDurenClient.CHAIN_ID_LINEA_SEPOLIA && !this.hasValidResolverForSetInfo()) {
622
+ return { calls: [] };
623
+ }
624
+ const resolver = chainId === AIAgentL2ENSDurenClient.CHAIN_ID_LINEA_MAINNET
625
+ ? this.getEnsRegistryAddress()
626
+ : this.getEnsResolverAddress();
627
+ const clean = (s) => (s || '').trim().toLowerCase();
628
+ const parent = clean(params.orgName);
629
+ const label = clean(params.agentName).replace(/\s+/g, '-');
630
+ const ensFullName = `${label}.${parent}.eth`;
631
+ const childNode = namehash(ensFullName);
632
+ const calls = [];
633
+ const setAddrData = encodeFunctionData({
634
+ abi: [{ name: 'setAddr', type: 'function', stateMutability: 'nonpayable', inputs: [{ name: 'node', type: 'bytes32' }, { name: 'a', type: 'address' }], outputs: [] }],
635
+ functionName: 'setAddr',
636
+ args: [childNode, params.agentAddress],
637
+ });
638
+ calls.push({ to: resolver, data: setAddrData });
639
+ if (params.agentUrl?.trim()) {
640
+ calls.push({
641
+ to: resolver,
642
+ data: encodeFunctionData({
643
+ abi: [{ name: 'setText', type: 'function', stateMutability: 'nonpayable', inputs: [{ name: 'node', type: 'bytes32' }, { name: 'key', type: 'string' }, { name: 'value', type: 'string' }], outputs: [] }],
644
+ functionName: 'setText',
645
+ args: [childNode, 'url', params.agentUrl.trim()],
646
+ }),
647
+ });
648
+ }
649
+ if (params.agentDescription?.trim()) {
650
+ calls.push({
651
+ to: resolver,
652
+ data: encodeFunctionData({
653
+ abi: [{ name: 'setText', type: 'function', stateMutability: 'nonpayable', inputs: [{ name: 'node', type: 'bytes32' }, { name: 'key', type: 'string' }, { name: 'value', type: 'string' }], outputs: [] }],
654
+ functionName: 'setText',
655
+ args: [childNode, 'description', params.agentDescription.trim()],
656
+ }),
657
+ });
658
+ }
659
+ return { calls };
660
+ }
661
+ return super.prepareSetAgentNameInfoCalls(params);
662
+ }
663
+ /**
664
+ * Direct chain call for setting resolver address records
665
+ * Equivalent to: cast send resolver "setAddr(bytes32,uint256,bytes)" $NODE coinType encodedAddress
666
+ */
667
+ async setResolverAddrRecordDirect(name, coinType, address) {
668
+ console.log("AIAgentL2ENSDurenClient.setResolverAddrRecordDirect");
669
+ console.log("name:", name);
670
+ console.log("coinType:", coinType);
671
+ console.log("address:", address);
672
+ const resolverAddress = this.getEnsResolverAddress();
673
+ // ENS Resolver ABI for setAddr
674
+ const resolverAbi = [
675
+ {
676
+ "inputs": [
677
+ {
678
+ "internalType": "bytes32",
679
+ "name": "node",
680
+ "type": "bytes32"
681
+ },
682
+ {
683
+ "internalType": "uint256",
684
+ "name": "coinType",
685
+ "type": "uint256"
686
+ },
687
+ {
688
+ "internalType": "bytes",
689
+ "name": "a",
690
+ "type": "bytes"
691
+ }
692
+ ],
693
+ "name": "setAddr",
694
+ "outputs": [],
695
+ "stateMutability": "nonpayable",
696
+ "type": "function"
697
+ }
698
+ ];
699
+ // Calculate namehash for the subdomain
700
+ const node = namehash(name);
701
+ // Encode the address according to the coin type
702
+ // For Base Sepolia (coinType 2147568164), we need to encode as bytes
703
+ let encodedAddress;
704
+ if (coinType === 2147568164) {
705
+ // Base Sepolia coin type - encode as bytes
706
+ // Equivalent to: $(cast abi-encode "f(address)" 0xYourBaseAddress)
707
+ encodedAddress = encodeFunctionData({
708
+ abi: [{ "inputs": [{ "internalType": "address", "name": "addr", "type": "address" }], "name": "f", "outputs": [], "stateMutability": "nonpayable", "type": "function" }],
709
+ functionName: 'f',
710
+ args: [address]
711
+ });
712
+ }
713
+ else if (coinType === 60) {
714
+ // Ethereum coin type - encode as 20-byte address
715
+ encodedAddress = address.padEnd(66, '0');
716
+ }
717
+ else {
718
+ // Generic encoding for other coin types
719
+ encodedAddress = address.padEnd(66, '0');
720
+ }
721
+ console.log("node:", node);
722
+ console.log("encodedAddress:", encodedAddress);
723
+ // Encode the setAddr function call
724
+ const data = encodeFunctionData({
725
+ abi: resolverAbi,
726
+ functionName: 'setAddr',
727
+ args: [node, BigInt(coinType), encodedAddress]
728
+ });
729
+ return {
730
+ to: resolverAddress,
731
+ data
732
+ };
733
+ }
734
+ }
735
+ //# sourceMappingURL=AIAgentL2ENSDurenClient.js.map