Bytecode Debugger

Inspect calls, stack, memory, and storage instruction by instruction when source code is unavailable or you need to verify low-level execution.

Bytecode Debugger shows the instructions a transaction actually executes in the EVM. Use it when source code is unverified, Source Maps are incomplete, or you need to confirm a branch, external call, or the reason for a REVERT.

It does not replace Execution Trace: first use Trace to find the call you need to explain, then switch to Bytecode Mode to see what executes inside that call.

Features

FeatureWhat it does
InstructionsShows executed opcodes by contract address and locates the current instruction.
StackShows the current instruction's operands and calculation results.
MemoryShows call data, return data, or temporarily encoded values.
StorageShows storage slots and values visible at the current execution position.
Address and bytecodeSwitches between contracts involved in execution to confirm which contract owns the current opcode.
CommandsShows preset Stack, Memory, or Storage modification commands and returns to their associated instruction.

Common opcodes include CALL for an external call, SSTORE for a storage write, JUMPI for a conditional branch, and REVERT for a failed call. Do not draw a conclusion from an opcode alone: inspect the Stack, Memory, and surrounding instructions too.

Using Previous and Next in Instructions

The Previous and Next controls in the Instructions panel move one instruction backward or forward in the transaction's actual EVM execution sequence. They do not switch between calls.

  • Use Previous to inspect data prepared before a CALL, SSTORE, or REVERT.
  • Use Next to inspect changes to Stack, Memory, Storage, or later control flow after that instruction runs.
  • At the first or last instruction in this execution segment, the corresponding control is unavailable.

Commands appears only in modifiable Bytecode Mode. It lists changes already configured for Stack, Memory, or Storage; select one to return to its instruction and compare execution before and after the change.

Follow an example

The following continues the execution from the XPEPE transaction. In this transaction, an intermediate contract receives ETH after WETH.withdraw(...) and sends it onward. Assume this contract has no available source code: you can use bytecode to confirm how that ETH transfer occurs.

The example reuses Bytecode Debugger. Its mock data includes the intermediate contract, TokenStaker, UniswapV3Pool, and WETH addresses from the transaction; instructions such as PUSH1, MSTORE, JUMPI, SSTORE, and CALL; and the corresponding Stack, Memory, Storage, and Commands.

1. Enter Bytecode Mode from Trace

In Execution Trace, find the call after WETH.withdraw(...), enter Debugger, and open Bytecode Mode. Confirm that the selected execution position belongs to the intermediate contract rather than WETH itself.

2. Find the external call

Find CALL in Instructions. Use Previous to inspect how its data was prepared, then Next to inspect execution afterward. CALL means the EVM is about to execute an external call to another address; use the current contract address to determine who initiated it.

3. Confirm the call with Stack and Memory

Open Stack to verify the CALL target, transferred amount, and input/output ranges. Then inspect Memory: a native ETH transfer normally needs no function arguments, while encoded data in Memory indicates it may also call a function on the target contract.

4. Determine whether state changed or execution failed

Continue stepping through the instructions:

  • At SSTORE, inspect the slot in Storage before and after the write.
  • At JUMPI, use the Stack to determine which branch runs.
  • At REVERT, inspect the preceding instructions and Memory to identify the failure condition or return data.

This lets you establish which bytecode initiated the ETH transfer, whether it included call data, and whether execution wrote state or failed.

Recommendations

  • Narrow the scope in Execution Trace before opening Bytecode Mode; do not start at the first opcode in the entire transaction.
  • Answer one question at a time, such as “What is the target of this CALL?” or “Why did this REVERT execute?”
  • When source code is available, use Source Debugger to understand business logic first; use Bytecode Mode to verify low-level details.
  • To confirm whether on-chain data truly changed, return to State Changes.