web3-tools-mcp 1.5.0 → 2.0.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.
Files changed (109) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +346 -164
  3. package/dist/anvil.d.ts +1 -1
  4. package/dist/anvil.d.ts.map +1 -1
  5. package/dist/anvil.js +11 -9
  6. package/dist/anvil.js.map +1 -1
  7. package/dist/chain-meta.d.ts.map +1 -1
  8. package/dist/chain-meta.js +7 -3
  9. package/dist/chain-meta.js.map +1 -1
  10. package/dist/chains.d.ts +960 -0
  11. package/dist/chains.d.ts.map +1 -0
  12. package/dist/chains.js +108 -0
  13. package/dist/chains.js.map +1 -0
  14. package/dist/client.d.ts +10 -1717
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +33 -216
  17. package/dist/client.js.map +1 -1
  18. package/dist/http-server.d.ts +18 -0
  19. package/dist/http-server.d.ts.map +1 -0
  20. package/dist/http-server.js +89 -0
  21. package/dist/http-server.js.map +1 -0
  22. package/dist/index.js +77 -32
  23. package/dist/index.js.map +1 -1
  24. package/dist/kv-storage.d.ts +23 -0
  25. package/dist/kv-storage.d.ts.map +1 -0
  26. package/dist/kv-storage.js +69 -0
  27. package/dist/kv-storage.js.map +1 -0
  28. package/dist/oauth.d.ts +31 -0
  29. package/dist/oauth.d.ts.map +1 -0
  30. package/dist/oauth.js +227 -0
  31. package/dist/oauth.js.map +1 -0
  32. package/dist/preview.d.ts.map +1 -1
  33. package/dist/preview.js +14 -4
  34. package/dist/preview.js.map +1 -1
  35. package/dist/tools/advanced.d.ts +4 -4
  36. package/dist/tools/advanced.d.ts.map +1 -1
  37. package/dist/tools/advanced.js +228 -247
  38. package/dist/tools/advanced.js.map +1 -1
  39. package/dist/tools/balance.d.ts +1 -1
  40. package/dist/tools/balance.d.ts.map +1 -1
  41. package/dist/tools/balance.js +97 -103
  42. package/dist/tools/balance.js.map +1 -1
  43. package/dist/tools/contract-info.d.ts +3 -3
  44. package/dist/tools/contract-info.d.ts.map +1 -1
  45. package/dist/tools/contract-info.js +150 -161
  46. package/dist/tools/contract-info.js.map +1 -1
  47. package/dist/tools/contract.d.ts +4 -4
  48. package/dist/tools/contract.d.ts.map +1 -1
  49. package/dist/tools/contract.js +91 -110
  50. package/dist/tools/contract.js.map +1 -1
  51. package/dist/tools/ens.d.ts +6 -6
  52. package/dist/tools/ens.d.ts.map +1 -1
  53. package/dist/tools/ens.js +239 -297
  54. package/dist/tools/ens.js.map +1 -1
  55. package/dist/tools/gas.d.ts +4 -4
  56. package/dist/tools/gas.d.ts.map +1 -1
  57. package/dist/tools/gas.js +90 -138
  58. package/dist/tools/gas.js.map +1 -1
  59. package/dist/tools/index.d.ts +1 -1
  60. package/dist/tools/index.d.ts.map +1 -1
  61. package/dist/tools/logs.d.ts +1 -1
  62. package/dist/tools/logs.d.ts.map +1 -1
  63. package/dist/tools/logs.js +36 -37
  64. package/dist/tools/logs.js.map +1 -1
  65. package/dist/tools/signatures.d.ts.map +1 -1
  66. package/dist/tools/signatures.js +67 -89
  67. package/dist/tools/signatures.js.map +1 -1
  68. package/dist/tools/transactions.d.ts +48 -4
  69. package/dist/tools/transactions.d.ts.map +1 -1
  70. package/dist/tools/transactions.js +228 -44
  71. package/dist/tools/transactions.js.map +1 -1
  72. package/dist/types.d.ts +2 -1
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/utils.d.ts +3 -8
  75. package/dist/utils.d.ts.map +1 -1
  76. package/dist/utils.js +36 -98
  77. package/dist/utils.js.map +1 -1
  78. package/dist/wallet-client.d.ts +11 -1
  79. package/dist/wallet-client.d.ts.map +1 -1
  80. package/dist/wallet-client.js +27 -9
  81. package/dist/wallet-client.js.map +1 -1
  82. package/dist/walletconnect.d.ts +52 -0
  83. package/dist/walletconnect.d.ts.map +1 -0
  84. package/dist/walletconnect.js +221 -0
  85. package/dist/walletconnect.js.map +1 -0
  86. package/package.json +21 -9
  87. package/src/anvil.ts +15 -18
  88. package/src/chain-meta.ts +8 -4
  89. package/src/chains.ts +145 -0
  90. package/src/client.ts +39 -252
  91. package/src/http-server.ts +117 -0
  92. package/src/index.ts +98 -49
  93. package/src/kv-storage.ts +83 -0
  94. package/src/oauth.ts +270 -0
  95. package/src/preview.ts +15 -14
  96. package/src/tools/advanced.ts +195 -213
  97. package/src/tools/balance.ts +103 -108
  98. package/src/tools/contract-info.ts +163 -184
  99. package/src/tools/contract.ts +123 -144
  100. package/src/tools/ens.ts +290 -345
  101. package/src/tools/gas.ts +122 -170
  102. package/src/tools/index.ts +2 -2
  103. package/src/tools/logs.ts +45 -43
  104. package/src/tools/signatures.ts +68 -86
  105. package/src/tools/transactions.ts +283 -50
  106. package/src/types.ts +2 -15
  107. package/src/utils.ts +56 -127
  108. package/src/wallet-client.ts +31 -9
  109. package/src/walletconnect.ts +269 -0
package/src/tools/ens.ts CHANGED
@@ -1,21 +1,21 @@
1
- import { type Address, isAddress, namehash } from "viem";
2
- import { normalize } from "viem/ens";
3
- import { z } from "zod";
4
- import type { ChainName } from "../types.js";
5
- import { getClientManager, SUPPORTED_CHAINS } from "../client.js";
6
- import { createTool, formatResponse } from "../utils.js";
1
+ import { type Address, isAddress, namehash } from 'viem'
2
+ import { normalize } from 'viem/ens'
3
+ import { z } from 'zod'
4
+ import { getClientManager, SUPPORTED_CHAINS } from '../client.js'
5
+ import type { ChainName } from '../types.js'
6
+ import { createTool, formatResponse } from '../utils.js'
7
7
 
8
8
  // Base ENS Contract Addresses
9
9
  const BASE_ENS_CONTRACTS = {
10
- registry: "0xb94704422c2a1e396835a571837aa5ae53285a95" as Address,
11
- reverseRegistrar: "0x79ea96012eea67a83431f1701b3dff7e37f9e282" as Address,
12
- l2Resolver: "0xC6d566A56A1aFf6508b41f6c90ff131615583BCD" as Address,
13
- };
10
+ registry: '0xb94704422c2a1e396835a571837aa5ae53285a95' as Address,
11
+ reverseRegistrar: '0x79ea96012eea67a83431f1701b3dff7e37f9e282' as Address,
12
+ l2Resolver: '0xC6d566A56A1aFf6508b41f6c90ff131615583BCD' as Address
13
+ }
14
14
 
15
15
  // Helper function for Base ENS reverse resolution
16
16
  async function reverseResolveBase(address: Address): Promise<string | null> {
17
- const clientManager = getClientManager();
18
- const client = clientManager.getClient("base");
17
+ const clientManager = getClientManager()
18
+ const client = clientManager.getClient('base')
19
19
 
20
20
  try {
21
21
  // Get the reverse node from ReverseRegistrar
@@ -23,65 +23,65 @@ async function reverseResolveBase(address: Address): Promise<string | null> {
23
23
  address: BASE_ENS_CONTRACTS.reverseRegistrar,
24
24
  abi: [
25
25
  {
26
- name: "node",
27
- type: "function",
28
- stateMutability: "pure",
29
- inputs: [{ name: "addr", type: "address" }],
30
- outputs: [{ name: "", type: "bytes32" }],
31
- },
26
+ name: 'node',
27
+ type: 'function',
28
+ stateMutability: 'pure',
29
+ inputs: [{ name: 'addr', type: 'address' }],
30
+ outputs: [{ name: '', type: 'bytes32' }]
31
+ }
32
32
  ],
33
- functionName: "node",
34
- args: [address],
35
- });
33
+ functionName: 'node',
34
+ args: [address]
35
+ })
36
36
 
37
37
  // Query the L2Resolver for the name
38
38
  const name = await client.readContract({
39
39
  address: BASE_ENS_CONTRACTS.l2Resolver,
40
40
  abi: [
41
41
  {
42
- name: "name",
43
- type: "function",
44
- stateMutability: "view",
45
- inputs: [{ name: "node", type: "bytes32" }],
46
- outputs: [{ name: "", type: "string" }],
47
- },
42
+ name: 'name',
43
+ type: 'function',
44
+ stateMutability: 'view',
45
+ inputs: [{ name: 'node', type: 'bytes32' }],
46
+ outputs: [{ name: '', type: 'string' }]
47
+ }
48
48
  ],
49
- functionName: "name",
50
- args: [reverseNode as `0x${string}`],
51
- });
49
+ functionName: 'name',
50
+ args: [reverseNode as `0x${string}`]
51
+ })
52
52
 
53
- return name || null;
54
- } catch (error) {
55
- return null;
53
+ return name || null
54
+ } catch (_error) {
55
+ return null
56
56
  }
57
57
  }
58
58
 
59
59
  // Helper function for Base ENS forward resolution
60
60
  async function resolveNameBase(name: string): Promise<Address | null> {
61
- const clientManager = getClientManager();
62
- const client = clientManager.getClient("base");
61
+ const clientManager = getClientManager()
62
+ const client = clientManager.getClient('base')
63
63
 
64
64
  try {
65
- const node = namehash(name);
65
+ const node = namehash(name)
66
66
 
67
67
  // Get resolver from registry
68
68
  const resolver = await client.readContract({
69
69
  address: BASE_ENS_CONTRACTS.registry,
70
70
  abi: [
71
71
  {
72
- name: "resolver",
73
- type: "function",
74
- stateMutability: "view",
75
- inputs: [{ name: "node", type: "bytes32" }],
76
- outputs: [{ name: "", type: "address" }],
77
- },
72
+ name: 'resolver',
73
+ type: 'function',
74
+ stateMutability: 'view',
75
+ inputs: [{ name: 'node', type: 'bytes32' }],
76
+ outputs: [{ name: '', type: 'address' }]
77
+ }
78
78
  ],
79
- functionName: "resolver",
80
- args: [node],
81
- });
79
+ functionName: 'resolver',
80
+ args: [node]
81
+ })
82
82
 
83
- if (!resolver || resolver === "0x0000000000000000000000000000000000000000") {
84
- return null;
83
+ if (!resolver || resolver === '0x0000000000000000000000000000000000000000') {
84
+ return null
85
85
  }
86
86
 
87
87
  // Get address from resolver
@@ -89,49 +89,49 @@ async function resolveNameBase(name: string): Promise<Address | null> {
89
89
  address: resolver as Address,
90
90
  abi: [
91
91
  {
92
- name: "addr",
93
- type: "function",
94
- stateMutability: "view",
95
- inputs: [{ name: "node", type: "bytes32" }],
96
- outputs: [{ name: "", type: "address" }],
97
- },
92
+ name: 'addr',
93
+ type: 'function',
94
+ stateMutability: 'view',
95
+ inputs: [{ name: 'node', type: 'bytes32' }],
96
+ outputs: [{ name: '', type: 'address' }]
97
+ }
98
98
  ],
99
- functionName: "addr",
100
- args: [node],
101
- });
99
+ functionName: 'addr',
100
+ args: [node]
101
+ })
102
102
 
103
- return address as Address | null;
104
- } catch (error) {
105
- return null;
103
+ return address as Address | null
104
+ } catch (_error) {
105
+ return null
106
106
  }
107
107
  }
108
108
 
109
109
  // Helper function for Base ENS text records
110
110
  async function getTextRecordBase(name: string, key: string): Promise<string | null> {
111
- const clientManager = getClientManager();
112
- const client = clientManager.getClient("base");
111
+ const clientManager = getClientManager()
112
+ const client = clientManager.getClient('base')
113
113
 
114
114
  try {
115
- const node = namehash(name);
115
+ const node = namehash(name)
116
116
 
117
117
  // Get resolver from registry
118
118
  const resolver = await client.readContract({
119
119
  address: BASE_ENS_CONTRACTS.registry,
120
120
  abi: [
121
121
  {
122
- name: "resolver",
123
- type: "function",
124
- stateMutability: "view",
125
- inputs: [{ name: "node", type: "bytes32" }],
126
- outputs: [{ name: "", type: "address" }],
127
- },
122
+ name: 'resolver',
123
+ type: 'function',
124
+ stateMutability: 'view',
125
+ inputs: [{ name: 'node', type: 'bytes32' }],
126
+ outputs: [{ name: '', type: 'address' }]
127
+ }
128
128
  ],
129
- functionName: "resolver",
130
- args: [node],
131
- });
129
+ functionName: 'resolver',
130
+ args: [node]
131
+ })
132
132
 
133
- if (!resolver || resolver === "0x0000000000000000000000000000000000000000") {
134
- return null;
133
+ if (!resolver || resolver === '0x0000000000000000000000000000000000000000') {
134
+ return null
135
135
  }
136
136
 
137
137
  // Get text record from resolver
@@ -139,355 +139,300 @@ async function getTextRecordBase(name: string, key: string): Promise<string | nu
139
139
  address: resolver as Address,
140
140
  abi: [
141
141
  {
142
- name: "text",
143
- type: "function",
144
- stateMutability: "view",
142
+ name: 'text',
143
+ type: 'function',
144
+ stateMutability: 'view',
145
145
  inputs: [
146
- { name: "node", type: "bytes32" },
147
- { name: "key", type: "string" },
146
+ { name: 'node', type: 'bytes32' },
147
+ { name: 'key', type: 'string' }
148
148
  ],
149
- outputs: [{ name: "", type: "string" }],
150
- },
149
+ outputs: [{ name: '', type: 'string' }]
150
+ }
151
151
  ],
152
- functionName: "text",
153
- args: [node, key],
154
- });
152
+ functionName: 'text',
153
+ args: [node, key]
154
+ })
155
155
 
156
- return textRecord || null;
157
- } catch (error) {
158
- return null;
156
+ return textRecord || null
157
+ } catch (_error) {
158
+ return null
159
159
  }
160
160
  }
161
161
 
162
162
  const EnsResolveSchema = z.object({
163
163
  chain: z
164
164
  .enum(SUPPORTED_CHAINS)
165
- .default("mainnet")
166
- .describe("Blockchain network (defaults to mainnet, as ENS is primarily on Ethereum)"),
167
- name: z
168
- .string()
169
- .describe("ENS name to resolve to an address (e.g., 'vitalik.eth', 'example.eth')"),
170
- universalResolver: z
171
- .boolean()
172
- .optional()
173
- .describe("Use universal resolver for cross-chain resolution (defaults to true)"),
174
- });
165
+ .default('mainnet')
166
+ .describe('Blockchain network (defaults to mainnet, as ENS is primarily on Ethereum)'),
167
+ name: z.string().describe("ENS name to resolve to an address (e.g., 'vitalik.eth', 'example.eth')"),
168
+ universalResolver: z.boolean().optional().describe('Use universal resolver for cross-chain resolution (defaults to true)')
169
+ })
175
170
 
176
171
  const EnsReverseResolveSchema = z.object({
177
- chain: z
178
- .enum(SUPPORTED_CHAINS)
179
- .default("mainnet")
180
- .describe("Blockchain network (defaults to mainnet)"),
181
- address: z.string().describe("Ethereum address to resolve to an ENS name"),
182
- universalResolver: z
183
- .boolean()
184
- .optional()
185
- .describe("Use universal resolver for cross-chain resolution (defaults to true)"),
186
- });
172
+ chain: z.enum(SUPPORTED_CHAINS).default('mainnet').describe('Blockchain network (defaults to mainnet)'),
173
+ address: z.string().describe('Ethereum address to resolve to an ENS name'),
174
+ universalResolver: z.boolean().optional().describe('Use universal resolver for cross-chain resolution (defaults to true)')
175
+ })
187
176
 
188
177
  const EnsTextRecordSchema = z.object({
189
- chain: z
190
- .enum(SUPPORTED_CHAINS)
191
- .default("mainnet")
192
- .describe("Blockchain network (defaults to mainnet)"),
193
- name: z.string().describe("ENS name to query text records from"),
194
- key: z
195
- .string()
196
- .describe(
197
- "Text record key (e.g., 'avatar', 'description', 'email', 'url', 'com.twitter', 'com.github')"
198
- ),
199
- universalResolver: z
200
- .boolean()
201
- .optional()
202
- .describe("Use universal resolver for cross-chain resolution (defaults to true)"),
203
- });
178
+ chain: z.enum(SUPPORTED_CHAINS).default('mainnet').describe('Blockchain network (defaults to mainnet)'),
179
+ name: z.string().describe('ENS name to query text records from'),
180
+ key: z.string().describe("Text record key (e.g., 'avatar', 'description', 'email', 'url', 'com.twitter', 'com.github')"),
181
+ universalResolver: z.boolean().optional().describe('Use universal resolver for cross-chain resolution (defaults to true)')
182
+ })
204
183
 
205
184
  const EnsBatchResolveSchema = z.object({
206
- chain: z
207
- .enum(SUPPORTED_CHAINS)
208
- .default("mainnet")
209
- .describe("Blockchain network (defaults to mainnet)"),
210
- names: z
211
- .array(z.string())
212
- .describe("Array of ENS names to resolve to addresses in a single batch"),
213
- universalResolver: z
214
- .boolean()
215
- .optional()
216
- .describe("Use universal resolver for cross-chain resolution (defaults to true)"),
217
- });
185
+ chain: z.enum(SUPPORTED_CHAINS).default('mainnet').describe('Blockchain network (defaults to mainnet)'),
186
+ names: z.array(z.string()).describe('Array of ENS names to resolve to addresses in a single batch'),
187
+ universalResolver: z.boolean().optional().describe('Use universal resolver for cross-chain resolution (defaults to true)')
188
+ })
218
189
 
219
190
  export default {
220
191
  resolve_ens_name: createTool(
221
- "Resolve ENS Name to Address",
222
- "Resolve an ENS name to its Ethereum address. ENS names are human-readable identifiers (like vitalik.eth) that resolve to Ethereum addresses.",
192
+ 'Resolve ENS Name to Address',
193
+ 'Resolve an ENS name to its Ethereum address. ENS names are human-readable identifiers (like vitalik.eth) that resolve to Ethereum addresses.',
223
194
  EnsResolveSchema,
224
195
  async (args) => {
225
- try {
226
- // Normalize the ENS name
227
- const normalizedName = normalize(args.name);
228
-
229
- let address: Address | null = null;
230
-
231
- // Use Base-specific logic for Base chain
232
- if (args.chain === "base") {
233
- address = await resolveNameBase(normalizedName);
234
- } else {
235
- // Use viem's built-in ENS resolution for other chains
236
- const clientManager = getClientManager();
237
- const client = clientManager.getClient(args.chain as ChainName);
238
-
239
- address = await client.getEnsAddress({
240
- name: normalizedName,
241
- universalResolverAddress: args.universalResolver !== false ? undefined : undefined,
242
- });
243
- }
244
-
245
- if (!address) {
246
- return formatResponse({
247
- success: false,
248
- name: args.name,
249
- normalizedName,
250
- address: null,
251
- chain: args.chain,
252
- message: "ENS name does not resolve to an address",
253
- });
254
- }
196
+ // Normalize the ENS name
197
+ const normalizedName = normalize(args.name)
198
+
199
+ let address: Address | null = null
200
+
201
+ // Use Base-specific logic for Base chain
202
+ if (args.chain === 'base') {
203
+ address = await resolveNameBase(normalizedName)
204
+ } else {
205
+ // Use viem's built-in ENS resolution for other chains
206
+ const clientManager = getClientManager()
207
+ const client = clientManager.getClient(args.chain as ChainName)
208
+
209
+ address = await client.getEnsAddress({
210
+ name: normalizedName,
211
+ universalResolverAddress: args.universalResolver !== false ? undefined : undefined
212
+ })
213
+ }
255
214
 
215
+ if (!address) {
256
216
  return formatResponse({
257
- success: true,
217
+ success: false,
258
218
  name: args.name,
259
219
  normalizedName,
260
- address,
220
+ address: null,
261
221
  chain: args.chain,
262
- });
263
- } catch (error) {
264
- throw new Error(`Failed to resolve ENS name: ${error}`);
222
+ message: 'ENS name does not resolve to an address'
223
+ })
265
224
  }
225
+
226
+ return formatResponse({
227
+ success: true,
228
+ name: args.name,
229
+ normalizedName,
230
+ address,
231
+ chain: args.chain
232
+ })
266
233
  }
267
234
  ),
268
235
 
269
236
  reverse_resolve_ens: createTool(
270
- "Reverse Resolve Address to ENS Name",
271
- "Reverse resolve an Ethereum address to its primary ENS name. Returns the ENS name if the address has set a reverse record.",
237
+ 'Reverse Resolve Address to ENS Name',
238
+ 'Reverse resolve an Ethereum address to its primary ENS name. Returns the ENS name if the address has set a reverse record.',
272
239
  EnsReverseResolveSchema,
273
240
  async (args) => {
274
241
  if (!isAddress(args.address)) {
275
- throw new Error(`Invalid Ethereum address: ${args.address}`);
242
+ throw new Error(`Invalid Ethereum address: ${args.address}`)
276
243
  }
277
244
 
278
- try {
279
- let ensName: string | null = null;
280
-
281
- // Use Base-specific logic for Base chain
282
- if (args.chain === "base") {
283
- ensName = await reverseResolveBase(args.address as Address);
284
- } else {
285
- // Use viem's built-in ENS resolution for other chains
286
- const clientManager = getClientManager();
287
- const client = clientManager.getClient(args.chain as ChainName);
288
-
289
- ensName = await client.getEnsName({
290
- address: args.address as Address,
291
- universalResolverAddress: args.universalResolver !== false ? undefined : undefined,
292
- });
293
- }
245
+ let ensName: string | null = null
294
246
 
295
- if (!ensName) {
296
- return formatResponse({
297
- success: false,
298
- address: args.address,
299
- name: null,
300
- chain: args.chain,
301
- message: "Address does not have a primary ENS name set",
302
- });
303
- }
247
+ // Use Base-specific logic for Base chain
248
+ if (args.chain === 'base') {
249
+ ensName = await reverseResolveBase(args.address as Address)
250
+ } else {
251
+ // Use viem's built-in ENS resolution for other chains
252
+ const clientManager = getClientManager()
253
+ const client = clientManager.getClient(args.chain as ChainName)
254
+
255
+ ensName = await client.getEnsName({
256
+ address: args.address as Address,
257
+ universalResolverAddress: args.universalResolver !== false ? undefined : undefined
258
+ })
259
+ }
304
260
 
261
+ if (!ensName) {
305
262
  return formatResponse({
306
- success: true,
263
+ success: false,
307
264
  address: args.address,
308
- name: ensName,
265
+ name: null,
309
266
  chain: args.chain,
310
- });
311
- } catch (error) {
312
- throw new Error(`Failed to reverse resolve address: ${error}`);
267
+ message: 'Address does not have a primary ENS name set'
268
+ })
313
269
  }
270
+
271
+ return formatResponse({
272
+ success: true,
273
+ address: args.address,
274
+ name: ensName,
275
+ chain: args.chain
276
+ })
314
277
  }
315
278
  ),
316
279
 
317
280
  get_ens_text_record: createTool(
318
- "Get ENS Text Record",
281
+ 'Get ENS Text Record',
319
282
  "Retrieve a text record from an ENS name. Common keys include 'avatar', 'description', 'email', 'url', 'com.twitter', 'com.github'.",
320
283
  EnsTextRecordSchema,
321
284
  async (args) => {
322
- try {
323
- // Normalize the ENS name
324
- const normalizedName = normalize(args.name);
325
-
326
- let textRecord: string | null = null;
327
-
328
- // Use Base-specific logic for Base chain
329
- if (args.chain === "base") {
330
- textRecord = await getTextRecordBase(normalizedName, args.key);
331
- } else {
332
- // Use viem's built-in ENS resolution for other chains
333
- const clientManager = getClientManager();
334
- const client = clientManager.getClient(args.chain as ChainName);
335
-
336
- textRecord = await client.getEnsText({
337
- name: normalizedName,
338
- key: args.key,
339
- universalResolverAddress: args.universalResolver !== false ? undefined : undefined,
340
- });
341
- }
285
+ // Normalize the ENS name
286
+ const normalizedName = normalize(args.name)
342
287
 
343
- if (!textRecord) {
344
- return formatResponse({
345
- success: false,
346
- name: args.name,
347
- normalizedName,
348
- key: args.key,
349
- value: null,
350
- chain: args.chain,
351
- message: `Text record '${args.key}' not found for ${args.name}`,
352
- });
353
- }
288
+ let textRecord: string | null = null
289
+
290
+ // Use Base-specific logic for Base chain
291
+ if (args.chain === 'base') {
292
+ textRecord = await getTextRecordBase(normalizedName, args.key)
293
+ } else {
294
+ // Use viem's built-in ENS resolution for other chains
295
+ const clientManager = getClientManager()
296
+ const client = clientManager.getClient(args.chain as ChainName)
297
+
298
+ textRecord = await client.getEnsText({
299
+ name: normalizedName,
300
+ key: args.key,
301
+ universalResolverAddress: args.universalResolver !== false ? undefined : undefined
302
+ })
303
+ }
354
304
 
305
+ if (!textRecord) {
355
306
  return formatResponse({
356
- success: true,
307
+ success: false,
357
308
  name: args.name,
358
309
  normalizedName,
359
310
  key: args.key,
360
- value: textRecord,
311
+ value: null,
361
312
  chain: args.chain,
362
- });
363
- } catch (error) {
364
- throw new Error(`Failed to get ENS text record: ${error}`);
313
+ message: `Text record '${args.key}' not found for ${args.name}`
314
+ })
365
315
  }
316
+
317
+ return formatResponse({
318
+ success: true,
319
+ name: args.name,
320
+ normalizedName,
321
+ key: args.key,
322
+ value: textRecord,
323
+ chain: args.chain
324
+ })
366
325
  }
367
326
  ),
368
327
 
369
328
  get_ens_avatar: createTool(
370
- "Get ENS Avatar",
371
- "Get the avatar URI for an ENS name. Returns the avatar URL if set.",
329
+ 'Get ENS Avatar',
330
+ 'Get the avatar URI for an ENS name. Returns the avatar URL if set.',
372
331
  z.object({
373
- chain: z
374
- .enum(SUPPORTED_CHAINS)
375
- .default("mainnet")
376
- .describe("Blockchain network (defaults to mainnet)"),
377
- name: z.string().describe("ENS name to get avatar from"),
378
- universalResolver: z
379
- .boolean()
380
- .optional()
381
- .describe("Use universal resolver for cross-chain resolution (defaults to true)"),
332
+ chain: z.enum(SUPPORTED_CHAINS).default('mainnet').describe('Blockchain network (defaults to mainnet)'),
333
+ name: z.string().describe('ENS name to get avatar from'),
334
+ universalResolver: z.boolean().optional().describe('Use universal resolver for cross-chain resolution (defaults to true)')
382
335
  }),
383
336
  async (args) => {
384
- try {
385
- // Normalize the ENS name
386
- const normalizedName = normalize(args.name);
387
-
388
- let avatar: string | null = null;
389
-
390
- // Use Base-specific logic for Base chain
391
- if (args.chain === "base") {
392
- avatar = await getTextRecordBase(normalizedName, "avatar");
393
- } else {
394
- // Use viem's built-in ENS resolution for other chains
395
- const clientManager = getClientManager();
396
- const client = clientManager.getClient(args.chain as ChainName);
397
-
398
- avatar = await client.getEnsAvatar({
399
- name: normalizedName,
400
- universalResolverAddress: args.universalResolver !== false ? undefined : undefined,
401
- });
402
- }
403
-
404
- if (!avatar) {
405
- return formatResponse({
406
- success: false,
407
- name: args.name,
408
- normalizedName,
409
- avatar: null,
410
- chain: args.chain,
411
- message: `No avatar set for ${args.name}`,
412
- });
413
- }
337
+ // Normalize the ENS name
338
+ const normalizedName = normalize(args.name)
339
+
340
+ let avatar: string | null = null
341
+
342
+ // Use Base-specific logic for Base chain
343
+ if (args.chain === 'base') {
344
+ avatar = await getTextRecordBase(normalizedName, 'avatar')
345
+ } else {
346
+ // Use viem's built-in ENS resolution for other chains
347
+ const clientManager = getClientManager()
348
+ const client = clientManager.getClient(args.chain as ChainName)
349
+
350
+ avatar = await client.getEnsAvatar({
351
+ name: normalizedName,
352
+ universalResolverAddress: args.universalResolver !== false ? undefined : undefined
353
+ })
354
+ }
414
355
 
356
+ if (!avatar) {
415
357
  return formatResponse({
416
- success: true,
358
+ success: false,
417
359
  name: args.name,
418
360
  normalizedName,
419
- avatar,
361
+ avatar: null,
420
362
  chain: args.chain,
421
- });
422
- } catch (error) {
423
- throw new Error(`Failed to get ENS avatar: ${error}`);
363
+ message: `No avatar set for ${args.name}`
364
+ })
424
365
  }
366
+
367
+ return formatResponse({
368
+ success: true,
369
+ name: args.name,
370
+ normalizedName,
371
+ avatar,
372
+ chain: args.chain
373
+ })
425
374
  }
426
375
  ),
427
376
 
428
377
  batch_resolve_ens_names: createTool(
429
- "Batch Resolve ENS Names",
430
- "Resolve multiple ENS names to addresses in a single batch for efficiency.",
378
+ 'Batch Resolve ENS Names',
379
+ 'Resolve multiple ENS names to addresses in a single batch for efficiency.',
431
380
  EnsBatchResolveSchema,
432
381
  async (args) => {
433
- try {
434
- // Resolve all ENS names in parallel
435
- const results = await Promise.allSettled(
436
- args.names.map(async (name) => {
437
- const normalizedName = normalize(name);
438
- let address: Address | null = null;
439
-
440
- // Use Base-specific logic for Base chain
441
- if (args.chain === "base") {
442
- address = await resolveNameBase(normalizedName);
443
- } else {
444
- // Use viem's built-in ENS resolution for other chains
445
- const clientManager = getClientManager();
446
- const client = clientManager.getClient(args.chain as ChainName);
447
-
448
- address = await client.getEnsAddress({
449
- name: normalizedName,
450
- universalResolverAddress: args.universalResolver !== false ? undefined : undefined,
451
- });
452
- }
453
-
454
- return {
455
- name,
456
- normalizedName,
457
- address,
458
- success: !!address,
459
- };
460
- })
461
- );
462
-
463
- // Process results
464
- const resolved = results.map((result, index) => {
465
- if (result.status === "fulfilled") {
466
- return result.value;
382
+ // Resolve all ENS names in parallel
383
+ const results = await Promise.allSettled(
384
+ args.names.map(async (name) => {
385
+ const normalizedName = normalize(name)
386
+ let address: Address | null = null
387
+
388
+ // Use Base-specific logic for Base chain
389
+ if (args.chain === 'base') {
390
+ address = await resolveNameBase(normalizedName)
391
+ } else {
392
+ // Use viem's built-in ENS resolution for other chains
393
+ const clientManager = getClientManager()
394
+ const client = clientManager.getClient(args.chain as ChainName)
395
+
396
+ address = await client.getEnsAddress({
397
+ name: normalizedName,
398
+ universalResolverAddress: args.universalResolver !== false ? undefined : undefined
399
+ })
467
400
  }
468
- return {
469
- name: args.names[index],
470
- normalizedName: args.names[index],
471
- address: null,
472
- success: false,
473
- error: result.reason instanceof Error ? result.reason.message : String(result.reason),
474
- };
475
- });
476
401
 
477
- const successCount = resolved.filter((r) => r.success).length;
478
- const failCount = resolved.filter((r) => !r.success).length;
402
+ return {
403
+ name,
404
+ normalizedName,
405
+ address,
406
+ success: !!address
407
+ }
408
+ })
409
+ )
479
410
 
480
- return formatResponse({
481
- success: true,
482
- chain: args.chain,
483
- totalNames: args.names.length,
484
- successfulResolves: successCount,
485
- failedResolves: failCount,
486
- results: resolved,
487
- });
488
- } catch (error) {
489
- throw new Error(`Failed to batch resolve ENS names: ${error}`);
490
- }
411
+ // Process results
412
+ const resolved = results.map((result, index) => {
413
+ if (result.status === 'fulfilled') {
414
+ return result.value
415
+ }
416
+ return {
417
+ name: args.names[index],
418
+ normalizedName: args.names[index],
419
+ address: null,
420
+ success: false,
421
+ error: result.reason instanceof Error ? result.reason.message : String(result.reason)
422
+ }
423
+ })
424
+
425
+ const successCount = resolved.filter((r) => r.success).length
426
+ const failCount = resolved.filter((r) => !r.success).length
427
+
428
+ return formatResponse({
429
+ success: true,
430
+ chain: args.chain,
431
+ totalNames: args.names.length,
432
+ successfulResolves: successCount,
433
+ failedResolves: failCount,
434
+ results: resolved
435
+ })
491
436
  }
492
- ),
493
- };
437
+ )
438
+ }