How to Solve Level 3 of the Ethernaut Gameโ€‚by@kamilpolak

How to Solve Level 3 of the Ethernaut Game

image
Kamil Polak HackerNoon profile picture

Kamil Polak

I am a huge enthusiast of cryptocurrency and blockchain technology.

In level 3 you have to play a game: coin flip. To complete this level you'll need to guess the correct outcome of a coin flip 10 times in a row.

So let's look at the code of the smart contract. We can see that there is only one function - flip.

The flip function takes a boolean value as its argument which represents a side of the coin that's being flipped and it returns a boolean that says whether the caller of this function won or not.

Let me also explain the following line of code.

uint256 blockValue = uint256(blockhash(block.number.sub(1)))

Blockhashis a global variable that takes blocknumber and returns hash of the given block when blocknumber is one of the 256 most recent blocks; otherwise returns zero.

block.number.sub(1) returns the block number of the last block. Why the last one, not the current one? Because at the time the function is called, the current block is not yet mined.

To sum up, the random number is being generated from the block hash or the hash of the previously mined block. This number is used as the source of randomness which ultimately influences the side of the flipped coin.

We can use something like a proxy contract and in the code, we could mimic the exact calculation of the hash of the previously mined block to generate the random number that we know this function is using. Next, we can copy the rest of the contract logic to get the same results.

contract HackCoinFlip{

    using SafeMath for uint256;
    CoinFlip public coinFlipContract;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

    constructor(address _coinFlipContract) public{
        coinFlipContract = CoinFlip(_coinFlipContract);
    }
    function makeGuess() public {

        uint256 blockValue = uint256(blockhash(block.number.sub(1)));
        uint256 coinFlip = blockValue.div(FACTOR);
        bool guess = coinFlip == 1 ? true : false;

        coinFlipContract.flip(guess);
    }
}

Note: in this case you need to use Remix IDE because it is not possible to upload an external smart contract.

To do that just copy&paste the CoinFlip and HackCoinFlip contracts. Keep in mind that before you deploy the contract you have to change the environment from JavaScript VM to Injected Web3 to be able to approve transactions using MetaMask.

image

Before we interact with smart contract let's check the initial state of consecutiveWins

image

As you can see it is 0. When you call the flip function in the HackCoinFlip contract the value will increase to 1. However, to win the game we need to guess the correct outcome of a coin flip 10 times in a row. This means that you have to call the function 10 times.

When you do this you should see something like this.

image

You are the winner!

Also published here: https://dev.to/kamilpolak/ethernaut-level-3-coin-flip-tutorial-1db1


Welcome to the Decentralized Internet Contest!

In level 3 you have to play a game: coin flip. To complete this level you'll need to guess the correct outcome of a coin flip 10 times in a row.

So let's look at the code of the smart contract. We can see that there is only one function - flip.

The flip function takes a boolean value as its argument which represents a side of the coin that's being flipped and it returns a boolean that says whether the caller of this function won or not.

Let me also explain the following line of code.

uint256 blockValue = uint256(blockhash(block.number.sub(1)))

Blockhashis a global variable that takes blocknumber and returns hash of the given block when blocknumber is one of the 256 most recent blocks; otherwise returns zero.

block.number.sub(1) returns the block number of the last block. Why the last one, not the current one? Because at the time the function is called, the current block is not yet mined.

To sum up, the random number is being generated from the block hash or the hash of the previously mined block. This number is used as the source of randomness which ultimately influences the side of the flipped coin.

We can use something like a proxy contract and in the code, we could mimic the exact calculation of the hash of the previously mined block to generate the random number that we know this function is using. Next, we can copy the rest of the contract logic to get the same results.

contract HackCoinFlip{

    using SafeMath for uint256;
    CoinFlip public coinFlipContract;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

    constructor(address _coinFlipContract) public{
        coinFlipContract = CoinFlip(_coinFlipContract);
    }
    function makeGuess() public {

        uint256 blockValue = uint256(blockhash(block.number.sub(1)));
        uint256 coinFlip = blockValue.div(FACTOR);
        bool guess = coinFlip == 1 ? true : false;

        coinFlipContract.flip(guess);
    }
}

Note: in this case you need to use Remix IDE because it is not possible to upload an external smart contract.

To do that just copy&paste the CoinFlip and HackCoinFlip contracts. Keep in mind that before you deploy the contract you have to change the environment from JavaScript VM to Injected Web3 to be able to approve transactions using MetaMask.

image

Before we interact with smart contract let's check the initial state of consecutiveWins

image

As you can see it is 0. When you call the flip function in the HackCoinFlip contract the value will increase to 1. However, to win the game we need to guess the correct outcome of a coin flip 10 times in a row. This means that you have to call the function 10 times.

When you do this you should see something like this.

image

You are the winner!

Also published here: https://dev.to/kamilpolak/ethernaut-level-3-coin-flip-tutorial-1db1

Comments

Signup or Login to Join the Discussion

Tags

Related Stories