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.
- package/CHANGELOG.md +95 -0
- package/README.md +346 -164
- 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 -216
- package/dist/client.js.map +1 -1
- package/dist/http-server.d.ts +18 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +89 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.js +77 -32
- package/dist/index.js.map +1 -1
- package/dist/kv-storage.d.ts +23 -0
- package/dist/kv-storage.d.ts.map +1 -0
- package/dist/kv-storage.js +69 -0
- package/dist/kv-storage.js.map +1 -0
- 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 +14 -4
- 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 +48 -4
- package/dist/tools/transactions.d.ts.map +1 -1
- package/dist/tools/transactions.js +228 -44
- package/dist/tools/transactions.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +3 -8
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +36 -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 +52 -0
- package/dist/walletconnect.d.ts.map +1 -0
- package/dist/walletconnect.js +221 -0
- package/dist/walletconnect.js.map +1 -0
- package/package.json +21 -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 -252
- package/src/http-server.ts +117 -0
- package/src/index.ts +98 -49
- package/src/kv-storage.ts +83 -0
- package/src/oauth.ts +270 -0
- package/src/preview.ts +15 -14
- 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 +283 -50
- package/src/types.ts +2 -15
- package/src/utils.ts +56 -127
- package/src/wallet-client.ts +31 -9
- package/src/walletconnect.ts +269 -0
package/src/tools/advanced.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { type Address, decodeAbiParameters, isAddress, parseAbiParameters } from 'viem'
|
|
2
2
|
import { z } from 'zod'
|
|
3
|
-
import
|
|
3
|
+
import { isAnvilInstalled, simulateCallWithTrace, traceTransactionWithAnvil } from '../anvil.js'
|
|
4
4
|
import { getClientManager, SUPPORTED_CHAINS } from '../client.js'
|
|
5
|
+
import type { ChainName } from '../types.js'
|
|
5
6
|
import { createTool, formatResponse, summarizeTrace } from '../utils.js'
|
|
6
|
-
import {
|
|
7
|
-
isAnvilInstalled,
|
|
8
|
-
traceTransactionWithAnvil,
|
|
9
|
-
simulateCallWithTrace
|
|
10
|
-
} from '../anvil.js'
|
|
11
7
|
|
|
12
8
|
export default {
|
|
13
9
|
get_storage_at: createTool(
|
|
@@ -17,9 +13,7 @@ export default {
|
|
|
17
13
|
chain: z.enum(SUPPORTED_CHAINS).describe('The blockchain network to use'),
|
|
18
14
|
address: z.string().describe('The contract address to inspect'),
|
|
19
15
|
slot: z.string().describe('Storage slot (hex string, e.g., "0x0")'),
|
|
20
|
-
abiType: z
|
|
21
|
-
.string()
|
|
22
|
-
.describe('ABI type for decoding (e.g., "uint256", "address", "bool", "bytes32")'),
|
|
16
|
+
abiType: z.string().describe('ABI type for decoding (e.g., "uint256", "address", "bool", "bytes32")'),
|
|
23
17
|
blockNumber: z.string().optional().describe('Block number (optional, defaults to latest)')
|
|
24
18
|
}),
|
|
25
19
|
async (args) => {
|
|
@@ -31,90 +25,86 @@ export default {
|
|
|
31
25
|
const client = clientManager.getClient(args.chain as ChainName)
|
|
32
26
|
const blockTag = args.blockNumber ? BigInt(args.blockNumber) : 'latest'
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
})
|
|
28
|
+
const storageValue = await client.getStorageAt({
|
|
29
|
+
address: args.address as Address,
|
|
30
|
+
slot: args.slot as `0x${string}`,
|
|
31
|
+
blockNumber: blockTag === 'latest' ? undefined : blockTag
|
|
32
|
+
})
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
if (!storageValue) {
|
|
35
|
+
throw new Error('No storage value found')
|
|
36
|
+
}
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
// Decode based on ABI type
|
|
39
|
+
let decodedValue: unknown
|
|
40
|
+
let formattedValue: string
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
decodedValue = null
|
|
91
|
-
formattedValue = 'Invalid ABI type'
|
|
92
|
-
}
|
|
93
|
-
} catch {
|
|
42
|
+
try {
|
|
43
|
+
switch (args.abiType.toLowerCase()) {
|
|
44
|
+
case 'uint256':
|
|
45
|
+
case 'uint': {
|
|
46
|
+
decodedValue = BigInt(storageValue)
|
|
47
|
+
formattedValue = (decodedValue as bigint).toString()
|
|
48
|
+
break
|
|
49
|
+
}
|
|
50
|
+
case 'int256':
|
|
51
|
+
case 'int': {
|
|
52
|
+
// Handle two's complement for negative numbers
|
|
53
|
+
const uint256Value = BigInt(storageValue)
|
|
54
|
+
const maxUint256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
|
|
55
|
+
decodedValue = uint256Value > maxUint256 / 2n ? uint256Value - maxUint256 - 1n : uint256Value
|
|
56
|
+
formattedValue = (decodedValue as bigint).toString()
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
case 'address': {
|
|
60
|
+
decodedValue = `0x${storageValue.slice(-40)}`
|
|
61
|
+
formattedValue = decodedValue as string
|
|
62
|
+
break
|
|
63
|
+
}
|
|
64
|
+
case 'bool': {
|
|
65
|
+
decodedValue = BigInt(storageValue) !== 0n
|
|
66
|
+
formattedValue = String(decodedValue)
|
|
67
|
+
break
|
|
68
|
+
}
|
|
69
|
+
case 'bytes32': {
|
|
70
|
+
decodedValue = storageValue
|
|
71
|
+
formattedValue = storageValue
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
default: {
|
|
75
|
+
// Try to decode as ABI parameters
|
|
76
|
+
try {
|
|
77
|
+
const parsedTypes = parseAbiParameters([args.abiType])
|
|
78
|
+
if (parsedTypes.length > 0) {
|
|
79
|
+
const decoded = decodeAbiParameters(parsedTypes, storageValue) as readonly unknown[]
|
|
80
|
+
decodedValue = decoded.length > 0 ? decoded[0] : null
|
|
81
|
+
formattedValue = decodedValue ? String(decodedValue) : 'No data'
|
|
82
|
+
} else {
|
|
94
83
|
decodedValue = null
|
|
95
|
-
formattedValue = '
|
|
84
|
+
formattedValue = 'Invalid ABI type'
|
|
96
85
|
}
|
|
97
|
-
|
|
86
|
+
} catch {
|
|
87
|
+
decodedValue = null
|
|
88
|
+
formattedValue = 'Failed to decode with custom ABI type'
|
|
98
89
|
}
|
|
90
|
+
break
|
|
99
91
|
}
|
|
100
|
-
} catch {
|
|
101
|
-
decodedValue = null
|
|
102
|
-
formattedValue = 'Failed to decode'
|
|
103
92
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
decodedValue,
|
|
108
|
-
formattedValue,
|
|
109
|
-
abiType: args.abiType,
|
|
110
|
-
slot: args.slot,
|
|
111
|
-
address: args.address,
|
|
112
|
-
chain: args.chain,
|
|
113
|
-
blockNumber: blockTag === 'latest' ? 'latest' : blockTag.toString()
|
|
114
|
-
})
|
|
115
|
-
} catch (error) {
|
|
116
|
-
throw new Error(`Failed to get storage: ${error}`)
|
|
93
|
+
} catch {
|
|
94
|
+
decodedValue = null
|
|
95
|
+
formattedValue = 'Failed to decode'
|
|
117
96
|
}
|
|
97
|
+
|
|
98
|
+
return formatResponse({
|
|
99
|
+
rawValue: storageValue,
|
|
100
|
+
decodedValue,
|
|
101
|
+
formattedValue,
|
|
102
|
+
abiType: args.abiType,
|
|
103
|
+
slot: args.slot,
|
|
104
|
+
address: args.address,
|
|
105
|
+
chain: args.chain,
|
|
106
|
+
blockNumber: blockTag === 'latest' ? 'latest' : blockTag.toString()
|
|
107
|
+
})
|
|
118
108
|
}
|
|
119
109
|
),
|
|
120
110
|
|
|
@@ -130,28 +120,24 @@ export default {
|
|
|
130
120
|
const client = clientManager.getClient(args.chain as ChainName)
|
|
131
121
|
const blockTag = args.blockNumber ? BigInt(args.blockNumber) : 'latest'
|
|
132
122
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
})
|
|
123
|
+
const block = await client.getBlock({
|
|
124
|
+
blockNumber: blockTag === 'latest' ? undefined : blockTag,
|
|
125
|
+
includeTransactions: false
|
|
126
|
+
})
|
|
138
127
|
|
|
139
|
-
|
|
140
|
-
|
|
128
|
+
const timestamp = Number(block.timestamp)
|
|
129
|
+
const date = new Date(timestamp * 1000)
|
|
141
130
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
} catch (error) {
|
|
153
|
-
throw new Error(`Failed to get block time: ${error}`)
|
|
154
|
-
}
|
|
131
|
+
return formatResponse({
|
|
132
|
+
blockNumber: block.number,
|
|
133
|
+
timestamp: block.timestamp,
|
|
134
|
+
timestampMs: timestamp * 1000,
|
|
135
|
+
dateIso: date.toISOString(),
|
|
136
|
+
dateReadable: date.toLocaleString(),
|
|
137
|
+
hash: block.hash,
|
|
138
|
+
parentHash: block.parentHash,
|
|
139
|
+
chain: args.chain
|
|
140
|
+
})
|
|
155
141
|
}
|
|
156
142
|
),
|
|
157
143
|
|
|
@@ -164,9 +150,7 @@ export default {
|
|
|
164
150
|
traceType: z
|
|
165
151
|
.enum(['trace', 'vmTrace', 'stateDiff'])
|
|
166
152
|
.optional()
|
|
167
|
-
.describe(
|
|
168
|
-
'Trace type: "trace" (call tree, recommended), "vmTrace" (VM execution), "stateDiff" (state changes)'
|
|
169
|
-
)
|
|
153
|
+
.describe('Trace type: "trace" (call tree, recommended), "vmTrace" (VM execution), "stateDiff" (state changes)')
|
|
170
154
|
.default('trace'),
|
|
171
155
|
useAnvil: z
|
|
172
156
|
.boolean()
|
|
@@ -183,92 +167,96 @@ export default {
|
|
|
183
167
|
const clientManager = getClientManager()
|
|
184
168
|
const client = clientManager.getClient(args.chain as ChainName)
|
|
185
169
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const receipt = await client.getTransactionReceipt({ hash: args.transactionHash as `0x${string}` })
|
|
170
|
+
// First get the transaction receipt to make sure it exists
|
|
171
|
+
const transaction = await client.getTransaction({ hash: args.transactionHash as `0x${string}` })
|
|
172
|
+
const receipt = await client.getTransactionReceipt({ hash: args.transactionHash as `0x${string}` })
|
|
190
173
|
|
|
191
|
-
|
|
192
|
-
|
|
174
|
+
let traceResult: unknown = null
|
|
175
|
+
let usedAnvil = false
|
|
193
176
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
177
|
+
// Map trace type to tracer name
|
|
178
|
+
const tracerMap: Record<string, 'callTracer' | 'prestateTracer' | 'stateDiffTracer'> = {
|
|
179
|
+
trace: 'callTracer',
|
|
180
|
+
vmTrace: 'prestateTracer',
|
|
181
|
+
stateDiff: 'stateDiffTracer'
|
|
182
|
+
}
|
|
183
|
+
const tracer = tracerMap[args.traceType ?? 'trace'] ?? 'callTracer'
|
|
201
184
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
185
|
+
// Try RPC tracing first (unless forceAnvil is true)
|
|
186
|
+
if (!args.useAnvil) {
|
|
187
|
+
try {
|
|
188
|
+
traceResult = await client.request({
|
|
189
|
+
method: 'debug_traceTransaction',
|
|
190
|
+
params: [args.transactionHash, { tracer }]
|
|
191
|
+
})
|
|
192
|
+
} catch (rpcError) {
|
|
193
|
+
// RPC tracing failed, will try Anvil fallback
|
|
194
|
+
const errorMessage = (rpcError as Error).message
|
|
195
|
+
if (
|
|
196
|
+
errorMessage.includes('not supported') ||
|
|
197
|
+
errorMessage.includes('not available') ||
|
|
198
|
+
errorMessage.includes('method not found') ||
|
|
199
|
+
errorMessage.includes('does not exist')
|
|
200
|
+
) {
|
|
201
|
+
// This is an expected error for public RPCs, try Anvil
|
|
202
|
+
traceResult = null
|
|
203
|
+
} else {
|
|
204
|
+
// Other error, store it but still try Anvil
|
|
205
|
+
traceResult = { rpcError: errorMessage }
|
|
224
206
|
}
|
|
225
207
|
}
|
|
208
|
+
}
|
|
226
209
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
210
|
+
// Fallback to Anvil if RPC tracing failed or was skipped
|
|
211
|
+
if (
|
|
212
|
+
traceResult === null ||
|
|
213
|
+
(traceResult && typeof traceResult === 'object' && 'rpcError' in traceResult) ||
|
|
214
|
+
args.useAnvil
|
|
215
|
+
) {
|
|
216
|
+
const anvilAvailable = await isAnvilInstalled()
|
|
217
|
+
if (anvilAvailable) {
|
|
218
|
+
usedAnvil = true // Mark as used before attempting (even if it fails)
|
|
219
|
+
try {
|
|
220
|
+
const forkUrl = clientManager.getRpcUrl(args.chain as ChainName)
|
|
221
|
+
const blockNumber = transaction.blockNumber ?? 0n
|
|
235
222
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
} catch (anvilError) {
|
|
244
|
-
// Anvil tracing also failed
|
|
245
|
-
traceResult = {
|
|
246
|
-
error: `Anvil tracing failed: ${(anvilError as Error).message}`,
|
|
247
|
-
rpcError: traceResult && typeof traceResult === 'object' && 'rpcError' in traceResult
|
|
223
|
+
traceResult = await traceTransactionWithAnvil(forkUrl, args.transactionHash, blockNumber, tracer, args.chain)
|
|
224
|
+
} catch (anvilError) {
|
|
225
|
+
// Anvil tracing also failed
|
|
226
|
+
traceResult = {
|
|
227
|
+
error: `Anvil tracing failed: ${(anvilError as Error).message}`,
|
|
228
|
+
rpcError:
|
|
229
|
+
traceResult && typeof traceResult === 'object' && 'rpcError' in traceResult
|
|
248
230
|
? (traceResult as { rpcError: string }).rpcError
|
|
249
231
|
: 'RPC does not support debug_traceTransaction'
|
|
250
|
-
}
|
|
251
232
|
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
233
|
+
}
|
|
234
|
+
} else if (!traceResult || (typeof traceResult === 'object' && 'rpcError' in traceResult)) {
|
|
235
|
+
// Anvil not available and RPC failed
|
|
236
|
+
traceResult = {
|
|
237
|
+
error:
|
|
238
|
+
'Tracing not available. Install Foundry (anvil) for local tracing: https://book.getfoundry.sh/getting-started/installation',
|
|
239
|
+
rpcError:
|
|
240
|
+
traceResult && typeof traceResult === 'object' && 'rpcError' in traceResult
|
|
257
241
|
? (traceResult as { rpcError: string }).rpcError
|
|
258
242
|
: 'RPC does not support debug_traceTransaction'
|
|
259
|
-
}
|
|
260
243
|
}
|
|
261
244
|
}
|
|
245
|
+
}
|
|
262
246
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
247
|
+
// Apply summarization if requested - focused on finding reverts
|
|
248
|
+
// Skip summarization only if traceResult is a plain error object (not a call trace with an error field)
|
|
249
|
+
const isPlainError =
|
|
250
|
+
traceResult &&
|
|
251
|
+
typeof traceResult === 'object' &&
|
|
252
|
+
'error' in traceResult &&
|
|
253
|
+
!('type' in traceResult) &&
|
|
254
|
+
!('calls' in traceResult)
|
|
255
|
+
const traceSummary =
|
|
256
|
+
args.summarize && traceResult && typeof traceResult === 'object' && !isPlainError ? summarizeTrace(traceResult) : null
|
|
270
257
|
|
|
271
|
-
|
|
258
|
+
const result =
|
|
259
|
+
args.summarize && traceSummary
|
|
272
260
|
? {
|
|
273
261
|
chain: args.chain,
|
|
274
262
|
transactionHash: args.transactionHash,
|
|
@@ -296,7 +284,7 @@ export default {
|
|
|
296
284
|
status: receipt.status,
|
|
297
285
|
gasUsed: receipt.gasUsed?.toString() || '0',
|
|
298
286
|
effectiveGasPrice: receipt.effectiveGasPrice?.toString() || '0',
|
|
299
|
-
logs: receipt.logs.map(log => ({
|
|
287
|
+
logs: receipt.logs.map((log) => ({
|
|
300
288
|
address: log.address,
|
|
301
289
|
topics: log.topics,
|
|
302
290
|
data: log.data
|
|
@@ -305,10 +293,7 @@ export default {
|
|
|
305
293
|
trace: traceResult
|
|
306
294
|
}
|
|
307
295
|
|
|
308
|
-
|
|
309
|
-
} catch (error) {
|
|
310
|
-
throw new Error(`Transaction trace failed: ${error}`)
|
|
311
|
-
}
|
|
296
|
+
return formatResponse(result)
|
|
312
297
|
}
|
|
313
298
|
),
|
|
314
299
|
|
|
@@ -327,10 +312,7 @@ export default {
|
|
|
327
312
|
.array(z.union([z.string(), z.number(), z.boolean()]))
|
|
328
313
|
.optional()
|
|
329
314
|
.describe('Function arguments (when using functionAbi)'),
|
|
330
|
-
from: z
|
|
331
|
-
.string()
|
|
332
|
-
.optional()
|
|
333
|
-
.describe('Sender address (defaults to zero address)'),
|
|
315
|
+
from: z.string().optional().describe('Sender address (defaults to zero address)'),
|
|
334
316
|
value: z.string().optional().describe('ETH value to send (in wei)'),
|
|
335
317
|
blockNumber: z.string().optional().describe('Block number to fork from (defaults to latest)'),
|
|
336
318
|
traceType: z
|
|
@@ -348,9 +330,7 @@ export default {
|
|
|
348
330
|
// Check if Anvil is installed
|
|
349
331
|
const anvilAvailable = await isAnvilInstalled()
|
|
350
332
|
if (!anvilAvailable) {
|
|
351
|
-
throw new Error(
|
|
352
|
-
'Anvil is not installed. Please install Foundry: https://book.getfoundry.sh/getting-started/installation'
|
|
353
|
-
)
|
|
333
|
+
throw new Error('Anvil is not installed. Please install Foundry: https://book.getfoundry.sh/getting-started/installation')
|
|
354
334
|
}
|
|
355
335
|
|
|
356
336
|
const clientManager = getClientManager()
|
|
@@ -375,31 +355,36 @@ export default {
|
|
|
375
355
|
}
|
|
376
356
|
}
|
|
377
357
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const value = args.value ? BigInt(args.value) : undefined
|
|
358
|
+
const blockNumber = args.blockNumber ? BigInt(args.blockNumber) : undefined
|
|
359
|
+
const value = args.value ? BigInt(args.value) : undefined
|
|
381
360
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
361
|
+
const traceResult = await simulateCallWithTrace(
|
|
362
|
+
forkUrl,
|
|
363
|
+
{
|
|
364
|
+
to: args.to,
|
|
365
|
+
data: calldata,
|
|
366
|
+
from: args.from,
|
|
367
|
+
value
|
|
368
|
+
},
|
|
369
|
+
blockNumber,
|
|
370
|
+
args.traceType
|
|
371
|
+
)
|
|
393
372
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
373
|
+
// Apply summarization if requested - focused on finding reverts
|
|
374
|
+
// Skip summarization only if trace is a plain error object (not a call trace with an error field)
|
|
375
|
+
const isPlainTraceError =
|
|
376
|
+
traceResult.trace &&
|
|
377
|
+
typeof traceResult.trace === 'object' &&
|
|
378
|
+
'error' in traceResult.trace &&
|
|
379
|
+
!('type' in traceResult.trace) &&
|
|
380
|
+
!('calls' in traceResult.trace)
|
|
381
|
+
const traceSummary =
|
|
382
|
+
args.summarize && traceResult.trace && typeof traceResult.trace === 'object' && !isPlainTraceError
|
|
399
383
|
? summarizeTrace(traceResult.trace)
|
|
400
384
|
: null
|
|
401
385
|
|
|
402
|
-
|
|
386
|
+
const result =
|
|
387
|
+
args.summarize && traceSummary
|
|
403
388
|
? {
|
|
404
389
|
chain: args.chain,
|
|
405
390
|
to: args.to,
|
|
@@ -422,10 +407,7 @@ export default {
|
|
|
422
407
|
trace: traceResult.trace
|
|
423
408
|
}
|
|
424
409
|
|
|
425
|
-
|
|
426
|
-
} catch (error) {
|
|
427
|
-
throw new Error(`Debug call failed: ${(error as Error).message}`)
|
|
428
|
-
}
|
|
410
|
+
return formatResponse(result)
|
|
429
411
|
}
|
|
430
412
|
)
|
|
431
413
|
}
|