web3-tools-mcp 1.3.4 → 1.4.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/README.md +51 -4
- package/dist/anvil.d.ts +34 -0
- package/dist/anvil.d.ts.map +1 -0
- package/dist/anvil.js +254 -0
- package/dist/anvil.js.map +1 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -0
- package/dist/client.js.map +1 -1
- package/dist/index.js +25 -5
- package/dist/index.js.map +1 -1
- package/dist/preview.d.ts +55 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +233 -0
- package/dist/preview.js.map +1 -0
- package/dist/tools/advanced.d.ts +67 -9
- package/dist/tools/advanced.d.ts.map +1 -1
- package/dist/tools/advanced.js +206 -67
- package/dist/tools/advanced.js.map +1 -1
- package/dist/tools/balance.d.ts +5 -5
- package/dist/tools/contract-info.d.ts +9 -9
- package/dist/tools/contract.d.ts +8 -8
- package/dist/tools/ens.d.ts +15 -15
- package/dist/tools/gas.d.ts +18 -18
- package/dist/tools/logs.d.ts +3 -3
- package/dist/tools/transactions.d.ts +9 -9
- package/dist/tools/transactions.d.ts.map +1 -1
- package/dist/tools/transactions.js +92 -113
- package/dist/tools/transactions.js.map +1 -1
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +76 -0
- package/dist/utils.js.map +1 -1
- package/dist/wallet-client.d.ts +83 -0
- package/dist/wallet-client.d.ts.map +1 -0
- package/dist/wallet-client.js +357 -0
- package/dist/wallet-client.js.map +1 -0
- package/package.json +9 -8
- package/src/anvil.ts +323 -0
- package/src/client.ts +14 -0
- package/src/index.ts +26 -5
- package/src/preview.ts +320 -0
- package/src/tools/advanced.ts +239 -70
- package/src/tools/transactions.ts +98 -125
- package/src/utils.ts +95 -0
- package/src/wallet-client.ts +380 -0
- package/dist/wallet-server.d.ts +0 -35
- package/dist/wallet-server.d.ts.map +0 -1
- package/dist/wallet-server.js +0 -232
- package/dist/wallet-server.js.map +0 -1
- package/public/wallet-app.js +0 -677
- package/public/wallet.html +0 -723
- package/src/wallet-server.ts +0 -283
|
@@ -1,18 +1,59 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
-
import {
|
|
3
|
-
import { SUPPORTED_CHAINS } from '../client.js'
|
|
4
|
-
import {
|
|
5
|
-
import { randomBytes } from 'crypto'
|
|
2
|
+
import { getWalletClient } from '../wallet-client.js'
|
|
3
|
+
import { getClientManager, SUPPORTED_CHAINS } from '../client.js'
|
|
4
|
+
import { encodeFunctionData, isAddress, parseAbiItem, parseUnits, type AbiFunction, type Address } from 'viem'
|
|
5
|
+
import { randomBytes } from 'node:crypto'
|
|
6
|
+
import type { ChainName } from '../types.js'
|
|
7
|
+
import { buildTxPreview, type RawTx } from '../preview.js'
|
|
6
8
|
import { createTool, formatResponse } from '../utils.js'
|
|
7
9
|
|
|
8
10
|
function generateRequestId(): string {
|
|
9
11
|
return randomBytes(16).toString('hex')
|
|
10
12
|
}
|
|
11
13
|
|
|
14
|
+
function requireAddress(label: string, address: string): Address {
|
|
15
|
+
if (!isAddress(address)) throw new Error(`Invalid ${label}: ${address}`)
|
|
16
|
+
return address
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function explorerTxUrl(chain: ChainName, txHash: unknown): string {
|
|
20
|
+
return `https://${getClientManager().getEtherscanDomain(chain)}/tx/${txHash}`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Send a transaction for signing, with a decoded + simulated preview attached so the
|
|
25
|
+
* wallet page can show what it actually does instead of raw calldata.
|
|
26
|
+
*/
|
|
27
|
+
async function requestSignature(chain: ChainName, tx: RawTx & { data?: string }) {
|
|
28
|
+
const wallet = getWalletClient()
|
|
29
|
+
await wallet.waitForSigner()
|
|
30
|
+
|
|
31
|
+
const preview = await buildTxPreview(chain, tx, wallet.getAddress())
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
txHash: await wallet.request({
|
|
35
|
+
id: generateRequestId(),
|
|
36
|
+
type: 'send_transaction',
|
|
37
|
+
chain,
|
|
38
|
+
data: { to: tx.to, value: tx.value ?? '0x0', ...(tx.data && { data: tx.data }) },
|
|
39
|
+
preview
|
|
40
|
+
}),
|
|
41
|
+
preview
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function failure(error: unknown, message: string) {
|
|
46
|
+
return formatResponse({
|
|
47
|
+
success: false,
|
|
48
|
+
error: error instanceof Error ? error.message : String(error),
|
|
49
|
+
message
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
12
53
|
export default {
|
|
13
54
|
send_native_token: createTool(
|
|
14
55
|
'Send Native Token',
|
|
15
|
-
'Send native tokens (ETH, MATIC, BNB, etc.) to an address.
|
|
56
|
+
'Send native tokens (ETH, MATIC, BNB, etc.) to an address. Simulates the transaction, then opens the browser wallet for approval.',
|
|
16
57
|
z.object({
|
|
17
58
|
chain: z.enum(SUPPORTED_CHAINS).describe('Blockchain network'),
|
|
18
59
|
to: z.string().describe('Recipient address'),
|
|
@@ -20,49 +61,30 @@ export default {
|
|
|
20
61
|
data: z.string().optional().describe('Optional hex-encoded data to include with transaction')
|
|
21
62
|
}),
|
|
22
63
|
async (args) => {
|
|
23
|
-
const walletServer = getWalletServer()
|
|
24
|
-
|
|
25
64
|
try {
|
|
26
|
-
|
|
27
|
-
const value =
|
|
65
|
+
const to = requireAddress('recipient address', args.to)
|
|
66
|
+
const value = `0x${parseUnits(args.amount, 18).toString(16)}`
|
|
28
67
|
|
|
29
|
-
const
|
|
30
|
-
id: generateRequestId(),
|
|
31
|
-
type: 'send_transaction' as const,
|
|
32
|
-
chain: args.chain,
|
|
33
|
-
data: {
|
|
34
|
-
to: args.to,
|
|
35
|
-
value,
|
|
36
|
-
...(args.data && { data: args.data })
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
console.error(`[Transaction] Sending ${args.amount} native token to ${args.to} on ${args.chain}`)
|
|
41
|
-
const txHash = await walletServer.sendTransaction(txRequest)
|
|
68
|
+
const { txHash, preview } = await requestSignature(args.chain as ChainName, { to, value, data: args.data })
|
|
42
69
|
|
|
43
70
|
return formatResponse({
|
|
44
71
|
success: true,
|
|
45
72
|
chain: args.chain,
|
|
46
73
|
transactionHash: txHash,
|
|
47
|
-
to
|
|
74
|
+
to,
|
|
48
75
|
amount: args.amount,
|
|
49
|
-
|
|
50
|
-
explorerUrl:
|
|
76
|
+
simulation: preview.simulation,
|
|
77
|
+
explorerUrl: explorerTxUrl(args.chain as ChainName, txHash)
|
|
51
78
|
})
|
|
52
79
|
} catch (error) {
|
|
53
|
-
|
|
54
|
-
return formatResponse({
|
|
55
|
-
success: false,
|
|
56
|
-
error: errorMessage,
|
|
57
|
-
message: 'Transaction failed or was rejected'
|
|
58
|
-
})
|
|
80
|
+
return failure(error, 'Transaction failed or was rejected')
|
|
59
81
|
}
|
|
60
82
|
}
|
|
61
83
|
),
|
|
62
84
|
|
|
63
85
|
send_erc20_token: createTool(
|
|
64
86
|
'Send ERC20 Token',
|
|
65
|
-
'Send ERC20 tokens to an address.
|
|
87
|
+
'Send ERC20 tokens to an address. Simulates the transfer, then opens the browser wallet for approval.',
|
|
66
88
|
z.object({
|
|
67
89
|
chain: z.enum(SUPPORTED_CHAINS).describe('Blockchain network'),
|
|
68
90
|
tokenAddress: z.string().describe('ERC20 token contract address'),
|
|
@@ -71,111 +93,71 @@ export default {
|
|
|
71
93
|
decimals: z.number().optional().default(18).describe('Token decimals (default: 18)')
|
|
72
94
|
}),
|
|
73
95
|
async (args) => {
|
|
74
|
-
const walletServer = getWalletServer()
|
|
75
|
-
|
|
76
96
|
try {
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
// ERC20 transfer(address to, uint256 amount)
|
|
81
|
-
const data = `0xa9059cbb${args.to.slice(2).padStart(64, '0')}${amountWei.toString(16).padStart(64, '0')}`
|
|
97
|
+
const tokenAddress = requireAddress('token address', args.tokenAddress)
|
|
98
|
+
const to = requireAddress('recipient address', args.to)
|
|
82
99
|
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
data: {
|
|
88
|
-
to: args.tokenAddress,
|
|
89
|
-
data,
|
|
90
|
-
value: '0x0'
|
|
91
|
-
}
|
|
92
|
-
}
|
|
100
|
+
const data = encodeFunctionData({
|
|
101
|
+
abi: [parseAbiItem('function transfer(address to, uint256 amount)')],
|
|
102
|
+
args: [to, parseUnits(args.amount, args.decimals ?? 18)]
|
|
103
|
+
})
|
|
93
104
|
|
|
94
|
-
|
|
95
|
-
const txHash = await walletServer.sendTransaction(txRequest)
|
|
105
|
+
const { txHash, preview } = await requestSignature(args.chain as ChainName, { to: tokenAddress, data, value: '0x0' })
|
|
96
106
|
|
|
97
107
|
return formatResponse({
|
|
98
108
|
success: true,
|
|
99
109
|
chain: args.chain,
|
|
100
110
|
transactionHash: txHash,
|
|
101
|
-
tokenAddress
|
|
102
|
-
to
|
|
111
|
+
tokenAddress,
|
|
112
|
+
to,
|
|
103
113
|
amount: args.amount,
|
|
104
|
-
|
|
105
|
-
explorerUrl:
|
|
114
|
+
simulation: preview.simulation,
|
|
115
|
+
explorerUrl: explorerTxUrl(args.chain as ChainName, txHash)
|
|
106
116
|
})
|
|
107
117
|
} catch (error) {
|
|
108
|
-
|
|
109
|
-
return formatResponse({
|
|
110
|
-
success: false,
|
|
111
|
-
error: errorMessage,
|
|
112
|
-
message: 'Token transfer failed or was rejected'
|
|
113
|
-
})
|
|
118
|
+
return failure(error, 'Token transfer failed or was rejected')
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
121
|
),
|
|
117
122
|
|
|
118
123
|
call_contract_write: createTool(
|
|
119
124
|
'Call Contract (Write)',
|
|
120
|
-
'Call a state-changing contract function
|
|
125
|
+
'Call a state-changing contract function. Simulates the call, then opens the browser wallet for approval.',
|
|
121
126
|
z.object({
|
|
122
127
|
chain: z.enum(SUPPORTED_CHAINS).describe('Blockchain network'),
|
|
123
128
|
contractAddress: z.string().describe('Contract address'),
|
|
124
129
|
functionAbi: z.string().describe('Function ABI definition (e.g., "function transfer(address to, uint256 amount)")'),
|
|
125
|
-
args: z
|
|
126
|
-
|
|
130
|
+
args: z
|
|
131
|
+
.array(z.union([z.string(), z.number(), z.boolean()]))
|
|
132
|
+
.optional()
|
|
133
|
+
.describe('Function arguments in order matching the ABI signature'),
|
|
134
|
+
value: z.string().optional().describe('Optional native value to send with transaction (in ETH units, e.g., "0.1")')
|
|
127
135
|
}),
|
|
128
136
|
async (args) => {
|
|
129
|
-
const walletServer = getWalletServer()
|
|
130
|
-
|
|
131
137
|
try {
|
|
132
|
-
|
|
133
|
-
console.error(`[Transaction] Parsing ABI: ${args.functionAbi}`)
|
|
134
|
-
console.error(`[Transaction] Args: ${JSON.stringify(args.args)}`)
|
|
135
|
-
|
|
138
|
+
const contractAddress = requireAddress('contract address', args.contractAddress)
|
|
136
139
|
const abiItem = parseAbiItem(args.functionAbi) as AbiFunction
|
|
137
|
-
console.error(`[Transaction] Parsed function: ${abiItem.name}`)
|
|
138
140
|
|
|
139
141
|
const data = encodeFunctionData({
|
|
140
142
|
abi: [abiItem],
|
|
141
143
|
functionName: abiItem.name,
|
|
142
144
|
args: (args.args || []) as readonly unknown[]
|
|
143
145
|
})
|
|
144
|
-
|
|
146
|
+
const value = args.value ? `0x${parseUnits(args.value, 18).toString(16)}` : '0x0'
|
|
145
147
|
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
const txRequest = {
|
|
149
|
-
id: generateRequestId(),
|
|
150
|
-
type: 'send_transaction' as const,
|
|
151
|
-
chain: args.chain,
|
|
152
|
-
data: {
|
|
153
|
-
to: args.contractAddress,
|
|
154
|
-
data,
|
|
155
|
-
value: valueHex
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
console.error(`[Transaction] Calling ${abiItem.name}() on ${args.contractAddress} (${args.chain})`)
|
|
160
|
-
const txHash = await walletServer.sendTransaction(txRequest)
|
|
148
|
+
const { txHash, preview } = await requestSignature(args.chain as ChainName, { to: contractAddress, data, value })
|
|
161
149
|
|
|
162
150
|
return formatResponse({
|
|
163
151
|
success: true,
|
|
164
152
|
chain: args.chain,
|
|
165
153
|
transactionHash: txHash,
|
|
166
|
-
contractAddress
|
|
154
|
+
contractAddress,
|
|
167
155
|
functionName: abiItem.name,
|
|
168
|
-
|
|
169
|
-
explorerUrl:
|
|
156
|
+
simulation: preview.simulation,
|
|
157
|
+
explorerUrl: explorerTxUrl(args.chain as ChainName, txHash)
|
|
170
158
|
})
|
|
171
159
|
} catch (error) {
|
|
172
|
-
|
|
173
|
-
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
174
|
-
return formatResponse({
|
|
175
|
-
success: false,
|
|
176
|
-
error: errorMessage,
|
|
177
|
-
message: 'Contract call failed or was rejected'
|
|
178
|
-
})
|
|
160
|
+
return failure(error, 'Contract call failed or was rejected')
|
|
179
161
|
}
|
|
180
162
|
}
|
|
181
163
|
),
|
|
@@ -187,20 +169,13 @@ export default {
|
|
|
187
169
|
message: z.string().describe('Message to sign')
|
|
188
170
|
}),
|
|
189
171
|
async (args) => {
|
|
190
|
-
const walletServer = getWalletServer()
|
|
191
|
-
|
|
192
172
|
try {
|
|
193
|
-
const
|
|
173
|
+
const signature = await getWalletClient().request({
|
|
194
174
|
id: generateRequestId(),
|
|
195
|
-
type: 'sign_message'
|
|
175
|
+
type: 'sign_message',
|
|
196
176
|
chain: 'any',
|
|
197
|
-
data: {
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
console.error(`[Transaction] Signing message`)
|
|
203
|
-
const signature = await walletServer.sendTransaction(request)
|
|
177
|
+
data: { message: args.message }
|
|
178
|
+
})
|
|
204
179
|
|
|
205
180
|
return formatResponse({
|
|
206
181
|
success: true,
|
|
@@ -209,12 +184,7 @@ export default {
|
|
|
209
184
|
signatureType: 'personal_sign'
|
|
210
185
|
})
|
|
211
186
|
} catch (error) {
|
|
212
|
-
|
|
213
|
-
return formatResponse({
|
|
214
|
-
success: false,
|
|
215
|
-
error: errorMessage,
|
|
216
|
-
message: 'Message signing failed or was rejected'
|
|
217
|
-
})
|
|
187
|
+
return failure(error, 'Message signing failed or was rejected')
|
|
218
188
|
}
|
|
219
189
|
}
|
|
220
190
|
),
|
|
@@ -224,23 +194,26 @@ export default {
|
|
|
224
194
|
'Check if a wallet is connected to the browser interface',
|
|
225
195
|
z.object({}),
|
|
226
196
|
async () => {
|
|
227
|
-
const
|
|
228
|
-
const isConnected = walletServer.isConnected()
|
|
229
|
-
const port = walletServer.getPort()
|
|
197
|
+
const wallet = getWalletClient()
|
|
230
198
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
199
|
+
try {
|
|
200
|
+
await wallet.connect()
|
|
201
|
+
} catch (error) {
|
|
202
|
+
return failure(error, 'Wallet relay unavailable')
|
|
234
203
|
}
|
|
235
204
|
|
|
205
|
+
if (!wallet.isConnected()) wallet.openBrowser()
|
|
206
|
+
|
|
236
207
|
return formatResponse({
|
|
237
|
-
connected: isConnected,
|
|
238
|
-
|
|
239
|
-
|
|
208
|
+
connected: wallet.isConnected(),
|
|
209
|
+
address: wallet.getAddress(),
|
|
210
|
+
walletUrl: wallet.getUrl(),
|
|
211
|
+
openTab: wallet.getPageUrl(),
|
|
212
|
+
hosted: wallet.isRemote,
|
|
213
|
+
message: wallet.isConnected()
|
|
240
214
|
? 'Wallet is connected and ready to sign transactions'
|
|
241
|
-
: `No wallet connected.
|
|
215
|
+
: `No wallet connected. Open ${wallet.getUrl()} and connect your wallet.`
|
|
242
216
|
})
|
|
243
217
|
}
|
|
244
218
|
)
|
|
245
219
|
}
|
|
246
|
-
|
package/src/utils.ts
CHANGED
|
@@ -35,6 +35,101 @@ export function convertBigIntToString(obj: unknown): unknown {
|
|
|
35
35
|
return obj
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
|
|
39
|
+
// Summarize a call trace for compact output
|
|
40
|
+
export interface SummarizedCall {
|
|
41
|
+
type: string
|
|
42
|
+
from: string
|
|
43
|
+
to: string
|
|
44
|
+
selector?: string
|
|
45
|
+
error?: string
|
|
46
|
+
depth: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function summarizeTrace(trace: unknown): { hasError: boolean; errorPath: SummarizedCall[] | null; summary: string } {
|
|
50
|
+
// Use ref object to avoid TypeScript closure narrowing issues
|
|
51
|
+
const result: { errorPath: SummarizedCall[]; errorMessage: string } | null = findErrorInTrace(trace)
|
|
52
|
+
|
|
53
|
+
// Generate summary
|
|
54
|
+
let summary: string
|
|
55
|
+
if (result) {
|
|
56
|
+
const lastCall = result.errorPath[result.errorPath.length - 1]
|
|
57
|
+
summary = `REVERTED at depth ${lastCall.depth}: ${lastCall.to} (${lastCall.selector || 'unknown'}) - ${result.errorMessage}`
|
|
58
|
+
} else {
|
|
59
|
+
// For successful txs, just show top-level calls
|
|
60
|
+
const topCalls: string[] = []
|
|
61
|
+
const rootCall = trace as Record<string, unknown>
|
|
62
|
+
const subcalls = rootCall.calls as Record<string, unknown>[] | undefined
|
|
63
|
+
if (subcalls) {
|
|
64
|
+
for (const sub of subcalls) {
|
|
65
|
+
const type = sub.type as string
|
|
66
|
+
if (type !== 'DELEGATECALL') {
|
|
67
|
+
const input = sub.input as string | undefined
|
|
68
|
+
const selector = input && input.length >= 10 ? input.slice(0, 10) : '?'
|
|
69
|
+
topCalls.push(`${type} ${sub.to} (${selector})`)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
summary = `SUCCESS - ${topCalls.length} top-level calls: ${topCalls.slice(0, 5).join(', ')}${topCalls.length > 5 ? '...' : ''}`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
hasError: result !== null,
|
|
78
|
+
errorPath: result?.errorPath ?? null,
|
|
79
|
+
summary
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function findErrorInTrace(trace: unknown): { errorPath: SummarizedCall[]; errorMessage: string } | null {
|
|
84
|
+
if (!trace || typeof trace !== 'object') return null
|
|
85
|
+
|
|
86
|
+
function findError(call: Record<string, unknown>, path: SummarizedCall[]): { errorPath: SummarizedCall[]; errorMessage: string } | null {
|
|
87
|
+
const type = (call.type as string) || 'CALL'
|
|
88
|
+
const error = (call.error as string) || (call.revertReason as string)
|
|
89
|
+
const subcalls = call.calls as Record<string, unknown>[] | undefined
|
|
90
|
+
const input = call.input as string | undefined
|
|
91
|
+
|
|
92
|
+
// Skip DELEGATECALL for cleaner output
|
|
93
|
+
if (type === 'DELEGATECALL') {
|
|
94
|
+
if (subcalls) {
|
|
95
|
+
for (const subcall of subcalls) {
|
|
96
|
+
const result = findError(subcall, path)
|
|
97
|
+
if (result) return result
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const currentCall: SummarizedCall = {
|
|
104
|
+
type,
|
|
105
|
+
from: (call.from as string) || '',
|
|
106
|
+
to: (call.to as string) || '',
|
|
107
|
+
selector: input && input.length >= 10 ? input.slice(0, 10) : undefined,
|
|
108
|
+
error: error || undefined,
|
|
109
|
+
depth: path.length
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const newPath = [...path, currentCall]
|
|
113
|
+
|
|
114
|
+
// Check subcalls first (error might be deeper)
|
|
115
|
+
if (subcalls) {
|
|
116
|
+
for (const subcall of subcalls) {
|
|
117
|
+
const result = findError(subcall, newPath)
|
|
118
|
+
if (result) return result
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// If this call has an error and no subcall had one, this is the source
|
|
123
|
+
if (error) {
|
|
124
|
+
return { errorPath: newPath, errorMessage: error }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return findError(trace as Record<string, unknown>, [])
|
|
131
|
+
}
|
|
132
|
+
|
|
38
133
|
// Convert arguments to appropriate types based on ABI
|
|
39
134
|
export function convertArgumentsToTypes(
|
|
40
135
|
args: (string | number | boolean | null)[],
|