Understanding ABI Encoding for Dynamic Bytes in Solidity

Understanding ABI Encoding for Dynamic Bytes in Solidity
Share

Understanding ABI Encoding for Dynamic Bytes in Solidity

When dealing with dynamic types like bytes in Solidity, the EVM needs a specific way to know where the data starts and how long it is. Let's break down exactly how this works under the hood using a simple example.

The Scope & Setup

We will use a simple contract that takes dynamic bytes data and returns it directly:

Image

For this breakdown, we will set actionData to the following 8-byte value: 0x1122334455667788

The Raw vs. Pretty Calldata

When we execute this function, the transaction sends an encoded calldata payload that looks like a massive, unreadable string of hex characters:

 0x09c5eabe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000081122334455667788000000000000000000000000000000000000000000000000

Parsing the Noise with Foundry

Because raw calldata is incredibly difficult to read by eye, we use a helper tool from Foundry:

cast pretty-calldata 0x09c5eabe0000000000000...

This command splits the chaotic string into clean, readable 32-byte chunks, making it easy to track the layout of the ABI encoding

Here is what the terminal outputs:

Terminal view

Image

Note: The first 4 bytes 0x09c5eabe represent the function selector for execute(bytes) and it needs to be manually added to your calldata when using pretty-calldata on it.

ABI Encoding of Dynamic Parameters

The Solidity ABI encoder automatically structures dynamic parameters into two main areas: the reference (Offset) and the data section (Length + Actual Data).

1. The Offset (Chunk [000])

Image

  1. How counting works: The EVM starts counting from 0 relative to the beginning of the arguments block (immediately after the 4-byte selector).
  2. The Reason: The value here is 0x20 (which is 32 in decimal). This literally instructs the EVM: "Move 32 bytes forward from the start of the arguments block. At that exact position, you will find the dynamic data section."
  3. Key Realization: The offset does not point directly to the raw data. Instead, it points to a region that begins with the data's length, which is then immediately followed by the raw bytes.

2. The Length (Chunk [020])

Image

  1. The Reason: Because we jumped 32 bytes (0x20) forward as instructed by the offset, we arrive at chunk [020]. This chunk specifies the size of the dynamic data.
  2. The Value: 0x08, meaning our input data is exactly 8 bytes long (which matches 0x1122334455667788).

3. The Actual Data (Chunk [040])

Image

  1. The Reason: The EVM loads data immediately after reading the length size.
  2. Our actual 8-byte payload (1122334455667788) sits perfectly at the front of this 32-byte slot, with the remaining slots padded out with trailing zeros to satisfy the EVM's word alignment requirements.

Community members

[ Our community ]

[ Community hires ]