Ethernaut Lvl 8 Vault Walkthrough — How to read “private” variables in contract storage (with Truffle)

This is a in-depth series around Zeppelin team’s smart contract security puzzles. We learn key Solidity concepts to solve the puzzles 100% on your own.

Nicole Zhu
Published in
3 min readAug 24, 2018


In this level, we learn to read contract storage with Truffle console, to unlock a vault with a “privately” stored password.

How Ethereum Storage works

storage in Ethereum programming can mean 2 different things:

  1. how Ethereum stores contract data on the blockchain, and
  2. how Solidity stores global and local variables.

In this post, we’re dive into how Ethereum stores data on the blockchain.

Storage on Ethereum blockchain is 2²⁵⁶ slots, and each slot is 32 bytes.

Each smart contract has its own storage to reflect the state of the contract. The values in storage persist across different function calls. And each storage is tethered to the smart contract’s address.

How data is physically stored

Data is stored sequentially in these slots, in order of declaration.

Storage is optimized to save byte space. So if sequential variables will fit in a single 32-byte slot, they will share the same slot, indexing from the least significant bits (from the right).

A visualisation of this Ethereum storage and space optimization:

Notice that bool and uint16 share slot 0, indicating this contract also costs less gas to instantiate!

Accessing storage

Conveniently, Web3 allows you to reach into contract storage via: web3.eth.getStorageAt(contractAddress, slotNumber)

Detailed Walkthrough

Level Setup

  1. Notice you cannot step through the Remix debugger with live contracts. So let’s use a more powerful tool to interact with this contract. Follow this 8 minute Truffle & Ropsten tutorial to get acquainted with interacting with contracts using Truffle framework.


2. Compile your Vault.sol contract to get the local ABI. You can just deploy to local network — just make sure Ganache is open:

truffle deploy   // auto compiles and deploys to local network

The EVM will save your compiled contract inside the /build.

3. Open truffle console to Ropsten:

truffle console --network Ropsten

4. Notice that the “private” password is stored in the slot 2, at index 1

Access the storage slot belonging to the contract instance (deployed by Ethernaut) at index 1, by:

web3.eth.getStorageAt(instance.address, 1, (err,res)=>{console.log(res)});

Note: getStorageAt returns a promise.

5. Use a hex-to-string converter, or the web3.utils.hexToAscii helper function to convert the bytes32 variable into a human readable text, which reveals “A very strong secret password :)”

6. unlock() your contract with the bytes32 private password