Regions
A region represents a contiguous block of bytes in a specific EVM data location. Regions are the leaves of the pointer tree—the actual byte ranges that hold data.
Addressing schemes
The EVM uses two different models for organizing bytes, and regions reflect this:
Slice-based locations
Memory, calldata, returndata, and code are byte-addressable.
Regions in these locations use offset and length:
{
"location": "memory",
"offset": "0x40",
"length": 32
}
offset: byte position from the start (required)length: number of bytes (optional; may be computed or implied by type)
Slot-based locations
Storage, transient storage, and stack are organized in 32-byte
slots. Regions use slot:
{
"location": "storage",
"slot": 5
}
For storage and transient storage, values that don't fill a full slot can specify sub-slot positioning:
{
"location": "storage",
"slot": 0,
"offset": 12,
"length": 20
}
This addresses 20 bytes starting at byte 12 within slot 0—useful for packed storage.
Location-specific details
Memory
Memory is a simple byte array that grows as needed:
{
"location": "memory",
"offset": "0x80",
"length": 64
}
Memory addresses often come from the free memory pointer (stored at 0x40).
Storage
Storage persists between transactions. Slots are 32-byte words addressed by 256-bit keys:
{
"location": "storage",
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
Slot addresses can be literal numbers, hex strings, or computed expressions.
Stack
The EVM stack holds up to 1024 words. Slot 0 is the top:
{
"location": "stack",
"slot": 0
}
Stack regions are typically read-only from a debugging perspective—you observe values but don't address sub-ranges.
Calldata
Function arguments arrive in calldata, read-only and byte-addressable:
{
"location": "calldata",
"offset": 4,
"length": 32
}
The first 4 bytes are typically the function selector; arguments follow.
Returndata
After a call, the returned data is accessible:
{
"location": "returndata",
"offset": 0,
"length": 32
}
Code
Contract bytecode can be read as data:
{
"location": "code",
"offset": 100,
"length": 32
}
This is used for immutable variables and other data embedded in bytecode.
Transient storage
Transient storage (EIP-1153) persists only within a transaction:
{
"location": "transient",
"slot": 0
}
Uses the same slot-based addressing as regular storage.
Naming regions
Any region can have a name that other parts of the pointer reference:
{
"name": "token-balance",
"location": "storage",
"slot": 3
}
Names enable:
- Reading the region's value with
{ "$read": "token-balance" } - Referencing properties with
{ ".slot": "token-balance" } - Building self-documenting pointer structures
Dynamic addresses
Region fields like offset, slot, and length can use expressions to
compute values at runtime. This enables pointers for dynamic data like arrays
and mappings.
For the full expression language including arithmetic, $keccak256, and value
reading, see expressions.
Learn more
For complete schemas for each location type, see the pointer region specification.