tevm-debugging
Debug transactions with EVM tracing, gas profiling, and error handling. Use when investigating contract behavior or test failures.
Files1
View on GitHubSKILL.md.claude/skills/tevm-debugging/SKILL.md
GitHubTevm Debugging
Basic Tracing
const trace = { steps: [], errors: [] }
const result = await client.tevmCall({
to: contractAddress,
data: '0x...',
onStep: (step, next) => {
trace.steps.push({
pc: step.pc,
opcode: step.opcode.name,
stack: step.stack.map(s => s.toString(16)),
depth: step.depth
})
next?.()
},
onAfterMessage: (result, next) => {
if (result.execResult.exceptionError) {
trace.errors.push({
error: result.execResult.exceptionError.error,
returnData: result.execResult.returnValue.toString('hex')
})
}
next?.()
}
})
Gas Profiling
const profile = {
opcodes: new Map(),
totalGas: 0n,
storageWrites: 0,
storageReads: 0
}
await client.tevmCall({
to: contractAddress,
data: '0x...',
onStep: (step, next) => {
const opName = step.opcode.name
// Track storage operations
if (opName === 'SSTORE') profile.storageWrites++
if (opName === 'SLOAD') profile.storageReads++
// Track gas by opcode
const gasCost = BigInt(step.opcode.fee)
const stats = profile.opcodes.get(opName) || { count: 0, gas: 0n }
stats.count++
stats.gas += gasCost
profile.opcodes.set(opName, stats)
profile.totalGas += gasCost
next?.()
}
})
console.log('Storage writes:', profile.storageWrites)
console.log('Gas by opcode:', profile.opcodes)
Error Handling
const result = await client.tevmCall({
to: contractAddress,
data: '0x...',
onAfterMessage: (result, next) => {
const err = result.execResult.exceptionError
if (!err) return next?.()
switch (err.error) {
case 'revert':
console.log('Reverted:', result.execResult.returnValue)
break
case 'out of gas':
console.log('Out of gas')
break
case 'invalid opcode':
console.log('Invalid opcode')
break
}
next?.()
}
})
// Check result
if (!result.errors && result.execResult.exceptionError) {
console.log('Failed:', result.execResult.exceptionError.error)
}
Time Manipulation
// Set next block timestamp
await client.setNextBlockTimestamp(Date.now() + 3600000) // 1 hour ahead
// Mine block with that timestamp
await client.mine({ blocks: 1 })
// Jump forward (via setAccount)
await client.setAccount({
address: '0x...', // special timestamp address
balance: BigInt(futureTimestamp)
})
State Snapshots
// Save state
const snap1 = await client.snapshot()
// Make changes
await contract.transfer(to, amount)
// Check state
const balance = await contract.balances(user)
// Revert if needed
await client.revert({ id: snap1 })
Access VM Directly
const vm = await client.getVm()
const result = await vm.runTx({
tx,
block,
skipNonce: true,
skipBalance: true
})