Market Cap: $2.8588T -5.21%
Volume(24h): $157.21B 50.24%
Fear & Greed Index:

38 - Fear

  • Market Cap: $2.8588T -5.21%
  • Volume(24h): $157.21B 50.24%
  • Fear & Greed Index:
  • Market Cap: $2.8588T -5.21%
Cryptos
Topics
Cryptospedia
News
CryptosTopics
Videos
Top Cryptospedia

Select Language

Select Language

Select Currency

Cryptos
Topics
Cryptospedia
News
CryptosTopics
Videos

How to Read Storage Variables from a Smart Contract?

Ethereum smart contracts store state in 32-byte slots; layout depends on variable order, types, inheritance, and compiler version—critical for accurate off-chain reads via `eth_getStorageAt`.

Jan 21, 2026 at 11:00 am

Understanding Storage Layout in Ethereum Smart Contracts

1. Every smart contract deployed on Ethereum maintains its state in persistent storage slots, each 32 bytes wide and indexed sequentially starting from slot 0.

2. The compiler assigns storage locations based on the declaration order of state variables, respecting type size and packing rules for efficiency.

3. Structs, arrays, and mappings introduce complexity: dynamic arrays store length in their slot and data at a keccak256-computed offset; mappings use keccak256(key, slot) to derive storage positions.

4. Solidity versions prior to 0.8.0 allowed tighter packing across variable boundaries, while newer versions enforce stricter alignment, affecting manual slot calculation accuracy.

5. Contract inheritance influences layout—variables from base contracts occupy lower slots, followed by those from derived contracts in linear order.

Direct On-Chain Reading via eth_getStorageAt

1. The JSON-RPC method eth_getStorageAt retrieves raw 32-byte values from a specific storage slot using contract address, slot index, and block identifier.

2. Slot indices must be computed manually or extracted from compilation artifacts like the Solidity-generated storage layout JSON found in the contract’s metadata or build-info files.

3. Tools such as hardhat-storage-layout or slither-print-storage automate slot mapping by parsing AST and bytecode, reducing human error.

4. When querying with infura or Alchemy endpoints, rate limits and archival node requirements apply—especially for historical slot values before contract upgrades or selfdestructs.

5. Hex-encoded responses require decoding: uint256 values appear left-padded, addresses are right-aligned in the last 20 bytes, and booleans map to 0x01 or 0x00.

Decoding Complex Types Manually

1. For static arrays, each element occupies one slot if it fits; otherwise, elements spill into consecutive slots following standard alignment rules.

2. Dynamic array data begins at keccak256(slot), where the first 32 bytes hold the array length and subsequent slots store elements contiguously starting at keccak256(slot)+1.

3. Mappings demand recomputing keccak256 for each key: for mapping(address => uint256) public balances, the slot for address 0xAbc… is keccak256(abi.encodePacked(0xAbc..., slot_index)).

4. Nested structures compound complexity—for example, a mapping to a struct requires computing the mapping slot first, then applying struct field offsets relative to that base.

5. Offsets inside structs follow the same rules as top-level variables: uint128 + uint128 packs into one slot, but adding a uint256 forces a new slot due to alignment constraints.

Using Foundry and Cast for Practical Inspection

1. cast storage command accepts a contract address and slot number, automatically fetching and optionally decoding values if ABI or layout is provided.

2. With --watch, cast monitors storage changes across blocks, useful for observing reentrancy or flash loan side effects in real time.

3. Foundry’s forge inspect outputs full storage layout including variable names, types, slot numbers, and byte offsets—no manual ABI parsing needed.

4. When source code is unavailable, reverse-engineering becomes necessary: analyzing SSTORE opcodes in transaction traces reveals which slots were written and when.

5. Custom scripts leveraging web3.py or ethers.js can batch-query multiple slots, format outputs as tables, and cross-reference with known proxy patterns like Transparent or UUPS.

Frequently Asked Questions

Q: Can I read storage from a contract without knowing its source code?A: Yes—using bytecode analysis, opcode tracing, or heuristics like common slot patterns for OpenZeppelin proxies or ERC-20 balances. However, interpretation remains ambiguous without context.

Q: Why does eth_getStorageAt return zero for a non-zero value I know exists?A: Possible causes include querying the wrong slot, using an outdated block number, targeting a proxy without forwarding to implementation, or reading uninitialized memory (which defaults to zero).

Q: Do storage reads cost gas when performed off-chain?A: No—eth_getStorageAt is a free RPC call. Gas costs apply only to on-chain reads executed within transactions or view functions.

Q: Is it safe to rely on storage slot numbers across compiler versions?A: Not guaranteed—Solidity updates may alter layout algorithms. Always verify against the exact compiler version and optimization settings used during deployment.

Disclaimer:info@kdj.com

The information provided is not trading advice. kdj.com does not assume any responsibility for any investments made based on the information provided in this article. Cryptocurrencies are highly volatile and it is highly recommended that you invest with caution after thorough research!

If you believe that the content used on this website infringes your copyright, please contact us immediately (info@kdj.com) and we will delete it promptly.

Related knowledge

See all articles

User not found or password invalid

Your input is correct