web3-tools-mcp 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/tools/gas.d.ts +99 -0
- package/dist/tools/gas.d.ts.map +1 -0
- package/dist/tools/gas.js +229 -0
- package/dist/tools/gas.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -1
- package/dist/tools/index.js.map +1 -1
- package/package.json +1 -1
- package/src/tools/gas.ts +267 -0
- package/src/tools/index.ts +3 -1
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@ A Model Context Protocol (MCP) server for blockchain interactions using [viem](h
|
|
|
6
6
|
|
|
7
7
|
- Multi-chain support (Ethereum, Arbitrum, Avalanche, Base, BNB Chain, Gnosis, Sonic, Optimism, Polygon, zkSync Era, Linea, Unichain)
|
|
8
8
|
- Smart contract interactions (read functions, ABI retrieval, source code)
|
|
9
|
+
- Contract simulation & gas estimation (simulate transactions, estimate costs)
|
|
10
|
+
- Real-time gas price tracking (legacy & EIP-1559)
|
|
9
11
|
- ENS resolution (names ↔ addresses, text records, avatars)
|
|
10
12
|
- Token balances (native & ERC20, batch queries)
|
|
11
13
|
- Event log queries with Hypersync acceleration
|
|
@@ -94,6 +96,11 @@ npx web3-tools-mcp
|
|
|
94
96
|
### Contract Interaction
|
|
95
97
|
- `call_contract_function` - Call view/pure functions (supports batch)
|
|
96
98
|
|
|
99
|
+
### Gas & Simulation
|
|
100
|
+
- `simulate_contract` - Simulate contract calls without broadcasting (includes gas estimate)
|
|
101
|
+
- `estimate_gas` - Estimate gas cost for any transaction
|
|
102
|
+
- `get_gas_price` - Get current gas prices (legacy & EIP-1559)
|
|
103
|
+
|
|
97
104
|
### ENS
|
|
98
105
|
- `resolve_ens_name` - ENS name → address
|
|
99
106
|
- `reverse_resolve_ens` - Address → ENS name
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
simulate_contract: {
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
schema: z.ZodObject<{
|
|
7
|
+
chain: z.ZodEnum<["mainnet", "arbitrum", "avalanche", "base", "bnb", "gnosis", "sonic", "optimism", "polygon", "zksync", "linea", "unichain", "localhost"]>;
|
|
8
|
+
contractAddress: z.ZodString;
|
|
9
|
+
functionAbi: z.ZodString;
|
|
10
|
+
args: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, "many">>;
|
|
11
|
+
from: z.ZodOptional<z.ZodString>;
|
|
12
|
+
value: z.ZodOptional<z.ZodString>;
|
|
13
|
+
blockNumber: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
16
|
+
contractAddress: string;
|
|
17
|
+
functionAbi: string;
|
|
18
|
+
blockNumber?: string | undefined;
|
|
19
|
+
from?: string | undefined;
|
|
20
|
+
value?: string | undefined;
|
|
21
|
+
args?: (string | number | boolean | null)[] | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
24
|
+
contractAddress: string;
|
|
25
|
+
functionAbi: string;
|
|
26
|
+
blockNumber?: string | undefined;
|
|
27
|
+
from?: string | undefined;
|
|
28
|
+
value?: string | undefined;
|
|
29
|
+
args?: (string | number | boolean | null)[] | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
handler: (args: {
|
|
32
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
33
|
+
contractAddress: string;
|
|
34
|
+
functionAbi: string;
|
|
35
|
+
blockNumber?: string | undefined;
|
|
36
|
+
from?: string | undefined;
|
|
37
|
+
value?: string | undefined;
|
|
38
|
+
args?: (string | number | boolean | null)[] | undefined;
|
|
39
|
+
}) => Promise<import("../types.js").ToolResult>;
|
|
40
|
+
};
|
|
41
|
+
estimate_gas: {
|
|
42
|
+
title: string;
|
|
43
|
+
description: string;
|
|
44
|
+
schema: z.ZodObject<{
|
|
45
|
+
chain: z.ZodEnum<["mainnet", "arbitrum", "avalanche", "base", "bnb", "gnosis", "sonic", "optimism", "polygon", "zksync", "linea", "unichain", "localhost"]>;
|
|
46
|
+
to: z.ZodOptional<z.ZodString>;
|
|
47
|
+
from: z.ZodOptional<z.ZodString>;
|
|
48
|
+
value: z.ZodOptional<z.ZodString>;
|
|
49
|
+
data: z.ZodOptional<z.ZodString>;
|
|
50
|
+
functionAbi: z.ZodOptional<z.ZodString>;
|
|
51
|
+
args: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, "many">>;
|
|
52
|
+
}, "strip", z.ZodTypeAny, {
|
|
53
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
54
|
+
from?: string | undefined;
|
|
55
|
+
to?: string | undefined;
|
|
56
|
+
value?: string | undefined;
|
|
57
|
+
data?: string | undefined;
|
|
58
|
+
args?: (string | number | boolean | null)[] | undefined;
|
|
59
|
+
functionAbi?: string | undefined;
|
|
60
|
+
}, {
|
|
61
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
62
|
+
from?: string | undefined;
|
|
63
|
+
to?: string | undefined;
|
|
64
|
+
value?: string | undefined;
|
|
65
|
+
data?: string | undefined;
|
|
66
|
+
args?: (string | number | boolean | null)[] | undefined;
|
|
67
|
+
functionAbi?: string | undefined;
|
|
68
|
+
}>;
|
|
69
|
+
handler: (args: {
|
|
70
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
71
|
+
from?: string | undefined;
|
|
72
|
+
to?: string | undefined;
|
|
73
|
+
value?: string | undefined;
|
|
74
|
+
data?: string | undefined;
|
|
75
|
+
args?: (string | number | boolean | null)[] | undefined;
|
|
76
|
+
functionAbi?: string | undefined;
|
|
77
|
+
}) => Promise<import("../types.js").ToolResult>;
|
|
78
|
+
};
|
|
79
|
+
get_gas_price: {
|
|
80
|
+
title: string;
|
|
81
|
+
description: string;
|
|
82
|
+
schema: z.ZodObject<{
|
|
83
|
+
chain: z.ZodEnum<["mainnet", "arbitrum", "avalanche", "base", "bnb", "gnosis", "sonic", "optimism", "polygon", "zksync", "linea", "unichain", "localhost"]>;
|
|
84
|
+
formatted: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
85
|
+
}, "strip", z.ZodTypeAny, {
|
|
86
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
87
|
+
formatted: boolean;
|
|
88
|
+
}, {
|
|
89
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
90
|
+
formatted?: boolean | undefined;
|
|
91
|
+
}>;
|
|
92
|
+
handler: (args: {
|
|
93
|
+
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
94
|
+
formatted: boolean;
|
|
95
|
+
}) => Promise<import("../types.js").ToolResult>;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
export default _default;
|
|
99
|
+
//# sourceMappingURL=gas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gas.d.ts","sourceRoot":"","sources":["../../src/tools/gas.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKxB,wBAoQE"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { isAddress, parseAbiItem, encodeFunctionData, decodeFunctionResult } from "viem";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getClientManager, SUPPORTED_CHAINS } from "../client.js";
|
|
4
|
+
import { convertArgumentsToTypes, createTool, formatResponse } from "../utils.js";
|
|
5
|
+
export default {
|
|
6
|
+
simulate_contract: createTool("Simulate Contract Call", "Simulate a contract call (including state-changing functions) without broadcasting. Returns simulation result and estimated gas.", z.object({
|
|
7
|
+
chain: z
|
|
8
|
+
.enum(SUPPORTED_CHAINS)
|
|
9
|
+
.describe("Blockchain network to simulate on"),
|
|
10
|
+
contractAddress: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe("Contract address to call"),
|
|
13
|
+
functionAbi: z
|
|
14
|
+
.string()
|
|
15
|
+
.describe('Function ABI signature (e.g., "function transfer(address to, uint256 amount)"). Can be any function type.'),
|
|
16
|
+
args: z
|
|
17
|
+
.array(z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Function arguments in order matching the ABI signature"),
|
|
20
|
+
from: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Sender address (defaults to zero address)"),
|
|
24
|
+
value: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("ETH value to send with the transaction (in wei as string)"),
|
|
28
|
+
blockNumber: z
|
|
29
|
+
.string()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Block number for simulation (defaults to latest)"),
|
|
32
|
+
}), async (args) => {
|
|
33
|
+
if (!isAddress(args.contractAddress)) {
|
|
34
|
+
throw new Error(`Invalid contract address: ${args.contractAddress}`);
|
|
35
|
+
}
|
|
36
|
+
if (args.from && !isAddress(args.from)) {
|
|
37
|
+
throw new Error(`Invalid from address: ${args.from}`);
|
|
38
|
+
}
|
|
39
|
+
const clientManager = getClientManager();
|
|
40
|
+
const client = clientManager.getClient(args.chain);
|
|
41
|
+
try {
|
|
42
|
+
const abiItem = parseAbiItem(args.functionAbi);
|
|
43
|
+
const convertedArgs = convertArgumentsToTypes(args.args || [], abiItem.inputs);
|
|
44
|
+
const blockTag = args.blockNumber ? BigInt(args.blockNumber) : undefined;
|
|
45
|
+
// Simulate the call
|
|
46
|
+
const result = await client.call({
|
|
47
|
+
to: args.contractAddress,
|
|
48
|
+
data: encodeFunctionData({
|
|
49
|
+
abi: [abiItem],
|
|
50
|
+
functionName: abiItem.name,
|
|
51
|
+
args: convertedArgs,
|
|
52
|
+
}),
|
|
53
|
+
account: args.from ? args.from : undefined,
|
|
54
|
+
value: args.value ? BigInt(args.value) : undefined,
|
|
55
|
+
blockNumber: blockTag,
|
|
56
|
+
});
|
|
57
|
+
// Also estimate gas
|
|
58
|
+
const gasEstimate = await client.estimateGas({
|
|
59
|
+
to: args.contractAddress,
|
|
60
|
+
data: encodeFunctionData({
|
|
61
|
+
abi: [abiItem],
|
|
62
|
+
functionName: abiItem.name,
|
|
63
|
+
args: convertedArgs,
|
|
64
|
+
}),
|
|
65
|
+
account: args.from ? args.from : undefined,
|
|
66
|
+
value: args.value ? BigInt(args.value) : undefined,
|
|
67
|
+
blockNumber: blockTag,
|
|
68
|
+
});
|
|
69
|
+
// Decode the result if the function has outputs
|
|
70
|
+
let decodedResult = result.data;
|
|
71
|
+
if (abiItem.outputs && abiItem.outputs.length > 0 && result.data) {
|
|
72
|
+
decodedResult = decodeFunctionResult({
|
|
73
|
+
abi: [abiItem],
|
|
74
|
+
functionName: abiItem.name,
|
|
75
|
+
data: result.data,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return formatResponse({
|
|
79
|
+
success: true,
|
|
80
|
+
chain: args.chain,
|
|
81
|
+
contractAddress: args.contractAddress,
|
|
82
|
+
functionName: abiItem.name,
|
|
83
|
+
result: decodedResult,
|
|
84
|
+
rawData: result.data,
|
|
85
|
+
gasEstimate: gasEstimate.toString(),
|
|
86
|
+
blockNumber: args.blockNumber || "latest",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
// Check if it's a revert error
|
|
91
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
92
|
+
return formatResponse({
|
|
93
|
+
success: false,
|
|
94
|
+
chain: args.chain,
|
|
95
|
+
contractAddress: args.contractAddress,
|
|
96
|
+
error: errorMessage,
|
|
97
|
+
reverted: errorMessage.includes("revert") || errorMessage.includes("execution reverted"),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}),
|
|
101
|
+
estimate_gas: createTool("Estimate Gas", "Estimate gas required for a transaction. Supports contract calls, transfers, and deployments.", z.object({
|
|
102
|
+
chain: z
|
|
103
|
+
.enum(SUPPORTED_CHAINS)
|
|
104
|
+
.describe("Blockchain network"),
|
|
105
|
+
to: z
|
|
106
|
+
.string()
|
|
107
|
+
.optional()
|
|
108
|
+
.describe("Recipient address (omit for contract deployment)"),
|
|
109
|
+
from: z
|
|
110
|
+
.string()
|
|
111
|
+
.optional()
|
|
112
|
+
.describe("Sender address (optional)"),
|
|
113
|
+
value: z
|
|
114
|
+
.string()
|
|
115
|
+
.optional()
|
|
116
|
+
.describe("ETH value to send (in wei as string)"),
|
|
117
|
+
data: z
|
|
118
|
+
.string()
|
|
119
|
+
.optional()
|
|
120
|
+
.describe("Transaction data (hex string for contract calls or deployment bytecode)"),
|
|
121
|
+
functionAbi: z
|
|
122
|
+
.string()
|
|
123
|
+
.optional()
|
|
124
|
+
.describe("Optional: Function ABI signature to encode call data automatically"),
|
|
125
|
+
args: z
|
|
126
|
+
.array(z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
127
|
+
.optional()
|
|
128
|
+
.describe("Optional: Function arguments (only used with functionAbi)"),
|
|
129
|
+
}), async (args) => {
|
|
130
|
+
if (args.to && !isAddress(args.to)) {
|
|
131
|
+
throw new Error(`Invalid to address: ${args.to}`);
|
|
132
|
+
}
|
|
133
|
+
if (args.from && !isAddress(args.from)) {
|
|
134
|
+
throw new Error(`Invalid from address: ${args.from}`);
|
|
135
|
+
}
|
|
136
|
+
const clientManager = getClientManager();
|
|
137
|
+
const client = clientManager.getClient(args.chain);
|
|
138
|
+
try {
|
|
139
|
+
let callData = args.data;
|
|
140
|
+
// If functionAbi is provided, encode the call data
|
|
141
|
+
if (args.functionAbi) {
|
|
142
|
+
const abiItem = parseAbiItem(args.functionAbi);
|
|
143
|
+
const convertedArgs = convertArgumentsToTypes(args.args || [], abiItem.inputs);
|
|
144
|
+
callData = encodeFunctionData({
|
|
145
|
+
abi: [abiItem],
|
|
146
|
+
functionName: abiItem.name,
|
|
147
|
+
args: convertedArgs,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const gasEstimate = await client.estimateGas({
|
|
151
|
+
to: args.to ? args.to : undefined,
|
|
152
|
+
account: args.from ? args.from : undefined,
|
|
153
|
+
value: args.value ? BigInt(args.value) : undefined,
|
|
154
|
+
data: callData,
|
|
155
|
+
});
|
|
156
|
+
return formatResponse({
|
|
157
|
+
success: true,
|
|
158
|
+
chain: args.chain,
|
|
159
|
+
gasEstimate: gasEstimate.toString(),
|
|
160
|
+
to: args.to,
|
|
161
|
+
from: args.from,
|
|
162
|
+
value: args.value,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
throw new Error(`Gas estimation failed: ${error}`);
|
|
167
|
+
}
|
|
168
|
+
}),
|
|
169
|
+
get_gas_price: createTool("Get Gas Price", "Get current gas prices for a chain. Returns both legacy gasPrice and EIP-1559 fees (maxFeePerGas, maxPriorityFeePerGas).", z.object({
|
|
170
|
+
chain: z
|
|
171
|
+
.enum(SUPPORTED_CHAINS)
|
|
172
|
+
.describe("Blockchain network"),
|
|
173
|
+
formatted: z
|
|
174
|
+
.boolean()
|
|
175
|
+
.optional()
|
|
176
|
+
.default(true)
|
|
177
|
+
.describe("Return prices in Gwei (default: true). If false, returns wei."),
|
|
178
|
+
}), async (args) => {
|
|
179
|
+
const clientManager = getClientManager();
|
|
180
|
+
const client = clientManager.getClient(args.chain);
|
|
181
|
+
try {
|
|
182
|
+
// Get both legacy and EIP-1559 gas prices
|
|
183
|
+
const [gasPrice, feeData] = await Promise.all([
|
|
184
|
+
client.getGasPrice(),
|
|
185
|
+
client.estimateFeesPerGas().catch(() => null), // Some chains don't support EIP-1559
|
|
186
|
+
]);
|
|
187
|
+
const formatPrice = (wei) => {
|
|
188
|
+
if (args.formatted) {
|
|
189
|
+
// Convert to Gwei (1 Gwei = 1e9 wei)
|
|
190
|
+
const gwei = Number(wei) / 1e9;
|
|
191
|
+
return `${gwei.toFixed(2)} Gwei`;
|
|
192
|
+
}
|
|
193
|
+
return wei.toString();
|
|
194
|
+
};
|
|
195
|
+
const response = {
|
|
196
|
+
chain: args.chain,
|
|
197
|
+
timestamp: new Date().toISOString(),
|
|
198
|
+
legacy: {
|
|
199
|
+
gasPrice: args.formatted ? formatPrice(gasPrice) : gasPrice.toString(),
|
|
200
|
+
gasPriceWei: gasPrice.toString(),
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
// Add EIP-1559 data if available
|
|
204
|
+
if (feeData) {
|
|
205
|
+
response.eip1559 = {
|
|
206
|
+
maxFeePerGas: args.formatted
|
|
207
|
+
? formatPrice(feeData.maxFeePerGas)
|
|
208
|
+
: feeData.maxFeePerGas.toString(),
|
|
209
|
+
maxPriorityFeePerGas: args.formatted
|
|
210
|
+
? formatPrice(feeData.maxPriorityFeePerGas)
|
|
211
|
+
: feeData.maxPriorityFeePerGas.toString(),
|
|
212
|
+
maxFeePerGasWei: feeData.maxFeePerGas.toString(),
|
|
213
|
+
maxPriorityFeePerGasWei: feeData.maxPriorityFeePerGas.toString(),
|
|
214
|
+
};
|
|
215
|
+
// Calculate estimated total cost for a standard 21000 gas transaction
|
|
216
|
+
const standardGasLimit = 21000n;
|
|
217
|
+
const estimatedCost = feeData.maxFeePerGas * standardGasLimit;
|
|
218
|
+
response.eip1559.estimatedCostFor21kGas = args.formatted
|
|
219
|
+
? `${(Number(estimatedCost) / 1e18).toFixed(6)} ETH`
|
|
220
|
+
: estimatedCost.toString();
|
|
221
|
+
}
|
|
222
|
+
return formatResponse(response);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
throw new Error(`Failed to get gas price: ${error}`);
|
|
226
|
+
}
|
|
227
|
+
}),
|
|
228
|
+
};
|
|
229
|
+
//# sourceMappingURL=gas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gas.js","sourceRoot":"","sources":["../../src/tools/gas.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAwBnE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,QAcjD"}
|
package/dist/tools/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import balanceTools from './balance.js';
|
|
|
3
3
|
import contractTools from './contract.js';
|
|
4
4
|
import contractInfoTools from './contract-info.js';
|
|
5
5
|
import ensTools from './ens.js';
|
|
6
|
+
import gasTools from './gas.js';
|
|
6
7
|
import logTools from './logs.js';
|
|
7
8
|
import signatureTools from './signatures.js';
|
|
8
9
|
const allToolDefinitions = {
|
|
@@ -12,7 +13,8 @@ const allToolDefinitions = {
|
|
|
12
13
|
...balanceTools,
|
|
13
14
|
...logTools,
|
|
14
15
|
...advancedTools,
|
|
15
|
-
...ensTools
|
|
16
|
+
...ensTools,
|
|
17
|
+
...gasTools
|
|
16
18
|
};
|
|
17
19
|
// Register all tools with the MCP server
|
|
18
20
|
export function registerAllTools(server) {
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAGA,OAAO,aAAa,MAAM,eAAe,CAAA;AACzC,OAAO,YAAY,MAAM,cAAc,CAAA;AACvC,OAAO,aAAa,MAAM,eAAe,CAAA;AACzC,OAAO,iBAAiB,MAAM,oBAAoB,CAAA;AAClD,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,QAAQ,MAAM,WAAW,CAAA;AAChC,OAAO,cAAc,MAAM,iBAAiB,CAAA;AAE5C,MAAM,kBAAkB,GAAG;IACzB,GAAG,cAAc;IACjB,GAAG,aAAa;IAChB,GAAG,iBAAiB;IACpB,GAAG,YAAY;IACf,GAAG,QAAQ;IACX,GAAG,aAAa;IAChB,GAAG,QAAQ;CACH,CAAA;AAEV,yCAAyC;AACzC,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QAC1D,MAAM,CAAC,YAAY,CACjB,IAAI,EACJ;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;SAC/B,EACD,KAAK,EAAE,IAAS,EAAE,MAA8D,EAAE,EAAE;YAClF,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACjC,CAAC,CACF,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAGA,OAAO,aAAa,MAAM,eAAe,CAAA;AACzC,OAAO,YAAY,MAAM,cAAc,CAAA;AACvC,OAAO,aAAa,MAAM,eAAe,CAAA;AACzC,OAAO,iBAAiB,MAAM,oBAAoB,CAAA;AAClD,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,QAAQ,MAAM,WAAW,CAAA;AAChC,OAAO,cAAc,MAAM,iBAAiB,CAAA;AAE5C,MAAM,kBAAkB,GAAG;IACzB,GAAG,cAAc;IACjB,GAAG,aAAa;IAChB,GAAG,iBAAiB;IACpB,GAAG,YAAY;IACf,GAAG,QAAQ;IACX,GAAG,aAAa;IAChB,GAAG,QAAQ;IACX,GAAG,QAAQ;CACH,CAAA;AAEV,yCAAyC;AACzC,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QAC1D,MAAM,CAAC,YAAY,CACjB,IAAI,EACJ;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;SAC/B,EACD,KAAK,EAAE,IAAS,EAAE,MAA8D,EAAE,EAAE;YAClF,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACjC,CAAC,CACF,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
package/package.json
CHANGED
package/src/tools/gas.ts
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { type AbiFunction, type Address, isAddress, parseAbiItem, encodeFunctionData, decodeFunctionResult } from "viem";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { ChainName } from "../types.js";
|
|
4
|
+
import { getClientManager, SUPPORTED_CHAINS } from "../client.js";
|
|
5
|
+
import { convertArgumentsToTypes, createTool, formatResponse } from "../utils.js";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
simulate_contract: createTool(
|
|
9
|
+
"Simulate Contract Call",
|
|
10
|
+
"Simulate a contract call (including state-changing functions) without broadcasting. Returns simulation result and estimated gas.",
|
|
11
|
+
z.object({
|
|
12
|
+
chain: z
|
|
13
|
+
.enum(SUPPORTED_CHAINS)
|
|
14
|
+
.describe("Blockchain network to simulate on"),
|
|
15
|
+
contractAddress: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe("Contract address to call"),
|
|
18
|
+
functionAbi: z
|
|
19
|
+
.string()
|
|
20
|
+
.describe(
|
|
21
|
+
'Function ABI signature (e.g., "function transfer(address to, uint256 amount)"). Can be any function type.'
|
|
22
|
+
),
|
|
23
|
+
args: z
|
|
24
|
+
.array(z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Function arguments in order matching the ABI signature"),
|
|
27
|
+
from: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Sender address (defaults to zero address)"),
|
|
31
|
+
value: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("ETH value to send with the transaction (in wei as string)"),
|
|
35
|
+
blockNumber: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Block number for simulation (defaults to latest)"),
|
|
39
|
+
}),
|
|
40
|
+
async (args) => {
|
|
41
|
+
if (!isAddress(args.contractAddress)) {
|
|
42
|
+
throw new Error(`Invalid contract address: ${args.contractAddress}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (args.from && !isAddress(args.from)) {
|
|
46
|
+
throw new Error(`Invalid from address: ${args.from}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const clientManager = getClientManager();
|
|
50
|
+
const client = clientManager.getClient(args.chain as ChainName);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const abiItem = parseAbiItem(args.functionAbi) as AbiFunction;
|
|
54
|
+
const convertedArgs = convertArgumentsToTypes(args.args || [], abiItem.inputs);
|
|
55
|
+
|
|
56
|
+
const blockTag = args.blockNumber ? BigInt(args.blockNumber) : undefined;
|
|
57
|
+
|
|
58
|
+
// Simulate the call
|
|
59
|
+
const result = await client.call({
|
|
60
|
+
to: args.contractAddress as Address,
|
|
61
|
+
data: encodeFunctionData({
|
|
62
|
+
abi: [abiItem],
|
|
63
|
+
functionName: abiItem.name,
|
|
64
|
+
args: convertedArgs,
|
|
65
|
+
}),
|
|
66
|
+
account: args.from ? (args.from as Address) : undefined,
|
|
67
|
+
value: args.value ? BigInt(args.value) : undefined,
|
|
68
|
+
blockNumber: blockTag,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Also estimate gas
|
|
72
|
+
const gasEstimate = await client.estimateGas({
|
|
73
|
+
to: args.contractAddress as Address,
|
|
74
|
+
data: encodeFunctionData({
|
|
75
|
+
abi: [abiItem],
|
|
76
|
+
functionName: abiItem.name,
|
|
77
|
+
args: convertedArgs,
|
|
78
|
+
}),
|
|
79
|
+
account: args.from ? (args.from as Address) : undefined,
|
|
80
|
+
value: args.value ? BigInt(args.value) : undefined,
|
|
81
|
+
blockNumber: blockTag,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Decode the result if the function has outputs
|
|
85
|
+
let decodedResult: unknown = result.data;
|
|
86
|
+
if (abiItem.outputs && abiItem.outputs.length > 0 && result.data) {
|
|
87
|
+
decodedResult = decodeFunctionResult({
|
|
88
|
+
abi: [abiItem],
|
|
89
|
+
functionName: abiItem.name,
|
|
90
|
+
data: result.data,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return formatResponse({
|
|
95
|
+
success: true,
|
|
96
|
+
chain: args.chain,
|
|
97
|
+
contractAddress: args.contractAddress,
|
|
98
|
+
functionName: abiItem.name,
|
|
99
|
+
result: decodedResult,
|
|
100
|
+
rawData: result.data,
|
|
101
|
+
gasEstimate: gasEstimate.toString(),
|
|
102
|
+
blockNumber: args.blockNumber || "latest",
|
|
103
|
+
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
// Check if it's a revert error
|
|
106
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
107
|
+
|
|
108
|
+
return formatResponse({
|
|
109
|
+
success: false,
|
|
110
|
+
chain: args.chain,
|
|
111
|
+
contractAddress: args.contractAddress,
|
|
112
|
+
error: errorMessage,
|
|
113
|
+
reverted: errorMessage.includes("revert") || errorMessage.includes("execution reverted"),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
),
|
|
118
|
+
|
|
119
|
+
estimate_gas: createTool(
|
|
120
|
+
"Estimate Gas",
|
|
121
|
+
"Estimate gas required for a transaction. Supports contract calls, transfers, and deployments.",
|
|
122
|
+
z.object({
|
|
123
|
+
chain: z
|
|
124
|
+
.enum(SUPPORTED_CHAINS)
|
|
125
|
+
.describe("Blockchain network"),
|
|
126
|
+
to: z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("Recipient address (omit for contract deployment)"),
|
|
130
|
+
from: z
|
|
131
|
+
.string()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Sender address (optional)"),
|
|
134
|
+
value: z
|
|
135
|
+
.string()
|
|
136
|
+
.optional()
|
|
137
|
+
.describe("ETH value to send (in wei as string)"),
|
|
138
|
+
data: z
|
|
139
|
+
.string()
|
|
140
|
+
.optional()
|
|
141
|
+
.describe("Transaction data (hex string for contract calls or deployment bytecode)"),
|
|
142
|
+
functionAbi: z
|
|
143
|
+
.string()
|
|
144
|
+
.optional()
|
|
145
|
+
.describe("Optional: Function ABI signature to encode call data automatically"),
|
|
146
|
+
args: z
|
|
147
|
+
.array(z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
148
|
+
.optional()
|
|
149
|
+
.describe("Optional: Function arguments (only used with functionAbi)"),
|
|
150
|
+
}),
|
|
151
|
+
async (args) => {
|
|
152
|
+
if (args.to && !isAddress(args.to)) {
|
|
153
|
+
throw new Error(`Invalid to address: ${args.to}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (args.from && !isAddress(args.from)) {
|
|
157
|
+
throw new Error(`Invalid from address: ${args.from}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const clientManager = getClientManager();
|
|
161
|
+
const client = clientManager.getClient(args.chain as ChainName);
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
let callData = args.data;
|
|
165
|
+
|
|
166
|
+
// If functionAbi is provided, encode the call data
|
|
167
|
+
if (args.functionAbi) {
|
|
168
|
+
const abiItem = parseAbiItem(args.functionAbi) as AbiFunction;
|
|
169
|
+
const convertedArgs = convertArgumentsToTypes(args.args || [], abiItem.inputs);
|
|
170
|
+
callData = encodeFunctionData({
|
|
171
|
+
abi: [abiItem],
|
|
172
|
+
functionName: abiItem.name,
|
|
173
|
+
args: convertedArgs,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const gasEstimate = await client.estimateGas({
|
|
178
|
+
to: args.to ? (args.to as Address) : undefined,
|
|
179
|
+
account: args.from ? (args.from as Address) : undefined,
|
|
180
|
+
value: args.value ? BigInt(args.value) : undefined,
|
|
181
|
+
data: callData as `0x${string}` | undefined,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return formatResponse({
|
|
185
|
+
success: true,
|
|
186
|
+
chain: args.chain,
|
|
187
|
+
gasEstimate: gasEstimate.toString(),
|
|
188
|
+
to: args.to,
|
|
189
|
+
from: args.from,
|
|
190
|
+
value: args.value,
|
|
191
|
+
});
|
|
192
|
+
} catch (error) {
|
|
193
|
+
throw new Error(`Gas estimation failed: ${error}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
),
|
|
197
|
+
|
|
198
|
+
get_gas_price: createTool(
|
|
199
|
+
"Get Gas Price",
|
|
200
|
+
"Get current gas prices for a chain. Returns both legacy gasPrice and EIP-1559 fees (maxFeePerGas, maxPriorityFeePerGas).",
|
|
201
|
+
z.object({
|
|
202
|
+
chain: z
|
|
203
|
+
.enum(SUPPORTED_CHAINS)
|
|
204
|
+
.describe("Blockchain network"),
|
|
205
|
+
formatted: z
|
|
206
|
+
.boolean()
|
|
207
|
+
.optional()
|
|
208
|
+
.default(true)
|
|
209
|
+
.describe("Return prices in Gwei (default: true). If false, returns wei."),
|
|
210
|
+
}),
|
|
211
|
+
async (args) => {
|
|
212
|
+
const clientManager = getClientManager();
|
|
213
|
+
const client = clientManager.getClient(args.chain as ChainName);
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
// Get both legacy and EIP-1559 gas prices
|
|
217
|
+
const [gasPrice, feeData] = await Promise.all([
|
|
218
|
+
client.getGasPrice(),
|
|
219
|
+
client.estimateFeesPerGas().catch(() => null), // Some chains don't support EIP-1559
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
const formatPrice = (wei: bigint): string => {
|
|
223
|
+
if (args.formatted) {
|
|
224
|
+
// Convert to Gwei (1 Gwei = 1e9 wei)
|
|
225
|
+
const gwei = Number(wei) / 1e9;
|
|
226
|
+
return `${gwei.toFixed(2)} Gwei`;
|
|
227
|
+
}
|
|
228
|
+
return wei.toString();
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const response: any = {
|
|
232
|
+
chain: args.chain,
|
|
233
|
+
timestamp: new Date().toISOString(),
|
|
234
|
+
legacy: {
|
|
235
|
+
gasPrice: args.formatted ? formatPrice(gasPrice) : gasPrice.toString(),
|
|
236
|
+
gasPriceWei: gasPrice.toString(),
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Add EIP-1559 data if available
|
|
241
|
+
if (feeData) {
|
|
242
|
+
response.eip1559 = {
|
|
243
|
+
maxFeePerGas: args.formatted
|
|
244
|
+
? formatPrice(feeData.maxFeePerGas)
|
|
245
|
+
: feeData.maxFeePerGas.toString(),
|
|
246
|
+
maxPriorityFeePerGas: args.formatted
|
|
247
|
+
? formatPrice(feeData.maxPriorityFeePerGas)
|
|
248
|
+
: feeData.maxPriorityFeePerGas.toString(),
|
|
249
|
+
maxFeePerGasWei: feeData.maxFeePerGas.toString(),
|
|
250
|
+
maxPriorityFeePerGasWei: feeData.maxPriorityFeePerGas.toString(),
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// Calculate estimated total cost for a standard 21000 gas transaction
|
|
254
|
+
const standardGasLimit = 21000n;
|
|
255
|
+
const estimatedCost = feeData.maxFeePerGas * standardGasLimit;
|
|
256
|
+
response.eip1559.estimatedCostFor21kGas = args.formatted
|
|
257
|
+
? `${(Number(estimatedCost) / 1e18).toFixed(6)} ETH`
|
|
258
|
+
: estimatedCost.toString();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return formatResponse(response);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
throw new Error(`Failed to get gas price: ${error}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
),
|
|
267
|
+
};
|
package/src/tools/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import balanceTools from './balance.js'
|
|
|
6
6
|
import contractTools from './contract.js'
|
|
7
7
|
import contractInfoTools from './contract-info.js'
|
|
8
8
|
import ensTools from './ens.js'
|
|
9
|
+
import gasTools from './gas.js'
|
|
9
10
|
import logTools from './logs.js'
|
|
10
11
|
import signatureTools from './signatures.js'
|
|
11
12
|
|
|
@@ -16,7 +17,8 @@ const allToolDefinitions = {
|
|
|
16
17
|
...balanceTools,
|
|
17
18
|
...logTools,
|
|
18
19
|
...advancedTools,
|
|
19
|
-
...ensTools
|
|
20
|
+
...ensTools,
|
|
21
|
+
...gasTools
|
|
20
22
|
} as const
|
|
21
23
|
|
|
22
24
|
// Register all tools with the MCP server
|