web3-tools-mcp 1.6.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.
- package/CHANGELOG.md +95 -0
- package/README.md +328 -234
- package/dist/anvil.d.ts +1 -1
- package/dist/anvil.d.ts.map +1 -1
- package/dist/anvil.js +11 -9
- package/dist/anvil.js.map +1 -1
- package/dist/chain-meta.d.ts.map +1 -1
- package/dist/chain-meta.js +7 -3
- package/dist/chain-meta.js.map +1 -1
- package/dist/chains.d.ts +960 -0
- package/dist/chains.d.ts.map +1 -0
- package/dist/chains.js +108 -0
- package/dist/chains.js.map +1 -0
- package/dist/client.d.ts +10 -1717
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +33 -218
- package/dist/client.js.map +1 -1
- package/dist/http-server.d.ts +6 -0
- package/dist/http-server.d.ts.map +1 -1
- package/dist/http-server.js +55 -40
- package/dist/http-server.js.map +1 -1
- package/dist/index.js +50 -29
- package/dist/index.js.map +1 -1
- package/dist/oauth.d.ts +31 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +227 -0
- package/dist/oauth.js.map +1 -0
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +2 -2
- package/dist/preview.js.map +1 -1
- package/dist/tools/advanced.d.ts +4 -4
- package/dist/tools/advanced.d.ts.map +1 -1
- package/dist/tools/advanced.js +228 -247
- package/dist/tools/advanced.js.map +1 -1
- package/dist/tools/balance.d.ts +1 -1
- package/dist/tools/balance.d.ts.map +1 -1
- package/dist/tools/balance.js +97 -103
- package/dist/tools/balance.js.map +1 -1
- package/dist/tools/contract-info.d.ts +3 -3
- package/dist/tools/contract-info.d.ts.map +1 -1
- package/dist/tools/contract-info.js +150 -161
- package/dist/tools/contract-info.js.map +1 -1
- package/dist/tools/contract.d.ts +4 -4
- package/dist/tools/contract.d.ts.map +1 -1
- package/dist/tools/contract.js +91 -110
- package/dist/tools/contract.js.map +1 -1
- package/dist/tools/ens.d.ts +6 -6
- package/dist/tools/ens.d.ts.map +1 -1
- package/dist/tools/ens.js +239 -297
- package/dist/tools/ens.js.map +1 -1
- package/dist/tools/gas.d.ts +4 -4
- package/dist/tools/gas.d.ts.map +1 -1
- package/dist/tools/gas.js +90 -138
- package/dist/tools/gas.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/logs.d.ts +1 -1
- package/dist/tools/logs.d.ts.map +1 -1
- package/dist/tools/logs.js +36 -37
- package/dist/tools/logs.js.map +1 -1
- package/dist/tools/signatures.d.ts.map +1 -1
- package/dist/tools/signatures.js +67 -89
- package/dist/tools/signatures.js.map +1 -1
- package/dist/tools/transactions.d.ts +35 -5
- package/dist/tools/transactions.d.ts.map +1 -1
- package/dist/tools/transactions.js +148 -74
- package/dist/tools/transactions.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +35 -98
- package/dist/utils.js.map +1 -1
- package/dist/wallet-client.d.ts +11 -1
- package/dist/wallet-client.d.ts.map +1 -1
- package/dist/wallet-client.js +27 -9
- package/dist/wallet-client.js.map +1 -1
- package/dist/walletconnect.d.ts +22 -1
- package/dist/walletconnect.d.ts.map +1 -1
- package/dist/walletconnect.js +101 -8
- package/dist/walletconnect.js.map +1 -1
- package/package.json +17 -9
- package/src/anvil.ts +15 -18
- package/src/chain-meta.ts +8 -4
- package/src/chains.ts +145 -0
- package/src/client.ts +39 -254
- package/src/http-server.ts +67 -44
- package/src/index.ts +77 -53
- package/src/oauth.ts +270 -0
- package/src/preview.ts +3 -12
- package/src/tools/advanced.ts +195 -213
- package/src/tools/balance.ts +103 -108
- package/src/tools/contract-info.ts +163 -184
- package/src/tools/contract.ts +123 -144
- package/src/tools/ens.ts +290 -345
- package/src/tools/gas.ts +122 -170
- package/src/tools/index.ts +2 -2
- package/src/tools/logs.ts +45 -43
- package/src/tools/signatures.ts +68 -86
- package/src/tools/transactions.ts +194 -87
- package/src/types.ts +1 -15
- package/src/utils.ts +52 -110
- package/src/wallet-client.ts +31 -9
- package/src/walletconnect.ts +119 -7
package/src/tools/ens.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { type Address, isAddress, namehash } from
|
|
2
|
-
import { normalize } from
|
|
3
|
-
import { z } from
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { createTool, formatResponse } from
|
|
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:
|
|
11
|
-
reverseRegistrar:
|
|
12
|
-
l2Resolver:
|
|
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(
|
|
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:
|
|
27
|
-
type:
|
|
28
|
-
stateMutability:
|
|
29
|
-
inputs: [{ name:
|
|
30
|
-
outputs: [{ name:
|
|
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:
|
|
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:
|
|
43
|
-
type:
|
|
44
|
-
stateMutability:
|
|
45
|
-
inputs: [{ name:
|
|
46
|
-
outputs: [{ name:
|
|
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:
|
|
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 (
|
|
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(
|
|
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:
|
|
73
|
-
type:
|
|
74
|
-
stateMutability:
|
|
75
|
-
inputs: [{ name:
|
|
76
|
-
outputs: [{ name:
|
|
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:
|
|
80
|
-
args: [node]
|
|
81
|
-
})
|
|
79
|
+
functionName: 'resolver',
|
|
80
|
+
args: [node]
|
|
81
|
+
})
|
|
82
82
|
|
|
83
|
-
if (!resolver || resolver ===
|
|
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:
|
|
93
|
-
type:
|
|
94
|
-
stateMutability:
|
|
95
|
-
inputs: [{ name:
|
|
96
|
-
outputs: [{ name:
|
|
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:
|
|
100
|
-
args: [node]
|
|
101
|
-
})
|
|
99
|
+
functionName: 'addr',
|
|
100
|
+
args: [node]
|
|
101
|
+
})
|
|
102
102
|
|
|
103
|
-
return address as Address | null
|
|
104
|
-
} catch (
|
|
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(
|
|
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:
|
|
123
|
-
type:
|
|
124
|
-
stateMutability:
|
|
125
|
-
inputs: [{ name:
|
|
126
|
-
outputs: [{ name:
|
|
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:
|
|
130
|
-
args: [node]
|
|
131
|
-
})
|
|
129
|
+
functionName: 'resolver',
|
|
130
|
+
args: [node]
|
|
131
|
+
})
|
|
132
132
|
|
|
133
|
-
if (!resolver || resolver ===
|
|
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:
|
|
143
|
-
type:
|
|
144
|
-
stateMutability:
|
|
142
|
+
name: 'text',
|
|
143
|
+
type: 'function',
|
|
144
|
+
stateMutability: 'view',
|
|
145
145
|
inputs: [
|
|
146
|
-
{ name:
|
|
147
|
-
{ name:
|
|
146
|
+
{ name: 'node', type: 'bytes32' },
|
|
147
|
+
{ name: 'key', type: 'string' }
|
|
148
148
|
],
|
|
149
|
-
outputs: [{ name:
|
|
150
|
-
}
|
|
149
|
+
outputs: [{ name: '', type: 'string' }]
|
|
150
|
+
}
|
|
151
151
|
],
|
|
152
|
-
functionName:
|
|
153
|
-
args: [node, key]
|
|
154
|
-
})
|
|
152
|
+
functionName: 'text',
|
|
153
|
+
args: [node, key]
|
|
154
|
+
})
|
|
155
155
|
|
|
156
|
-
return textRecord || null
|
|
157
|
-
} catch (
|
|
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(
|
|
166
|
-
.describe(
|
|
167
|
-
name: z
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
222
|
-
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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:
|
|
217
|
+
success: false,
|
|
258
218
|
name: args.name,
|
|
259
219
|
normalizedName,
|
|
260
|
-
address,
|
|
220
|
+
address: null,
|
|
261
221
|
chain: args.chain,
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
271
|
-
|
|
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
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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:
|
|
263
|
+
success: false,
|
|
307
264
|
address: args.address,
|
|
308
|
-
name:
|
|
265
|
+
name: null,
|
|
309
266
|
chain: args.chain,
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
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
|
-
|
|
323
|
-
|
|
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
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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:
|
|
307
|
+
success: false,
|
|
357
308
|
name: args.name,
|
|
358
309
|
normalizedName,
|
|
359
310
|
key: args.key,
|
|
360
|
-
value:
|
|
311
|
+
value: null,
|
|
361
312
|
chain: args.chain,
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
371
|
-
|
|
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
|
-
|
|
375
|
-
|
|
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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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:
|
|
358
|
+
success: false,
|
|
417
359
|
name: args.name,
|
|
418
360
|
normalizedName,
|
|
419
|
-
avatar,
|
|
361
|
+
avatar: null,
|
|
420
362
|
chain: args.chain,
|
|
421
|
-
|
|
422
|
-
|
|
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
|
-
|
|
430
|
-
|
|
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
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
478
|
-
|
|
402
|
+
return {
|
|
403
|
+
name,
|
|
404
|
+
normalizedName,
|
|
405
|
+
address,
|
|
406
|
+
success: !!address
|
|
407
|
+
}
|
|
408
|
+
})
|
|
409
|
+
)
|
|
479
410
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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
|
+
}
|