Ir para o conteúdo

Cara ou Coroa

Jogo simples de sorte (não é verdadeiramente aleatório).

Conceitos ensinados: - Pseudo-random com keccak256() - Hash de dados - Limitações da blockchain (determinismo)

Código

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

/**
 * @title CaraOuCoroa
 * @dev Jogo simples de sorte (não é verdadeiramente aleatório)
 * Ensina: keccak256 + hash + limitações da blockchain
 * 
 * ⚠️ IMPORTANTE: Isso NÃO é aleatoriedade verdadeira!
 * A blockchain é determinística, então qualquer um pode calcular o resultado
 * Use oráculos (VRF, Chainlink) para randomness real
 *
 * Como testar no Remix:
 * 1. Deploy no Remix VM.
 * 2. Chame jogar() e veja o retorno bool + evento Jogo.
 * 3. Chame jogarComNumero(123) e compare resultados em chamadas diferentes.
 * 4. Chame sortearAte(10) e confirme retorno entre 1 e 10.
 * 5. Tente sortearAte(0) para validar o require.
 */
contract CaraOuCoroa {

    /**
     * @dev Evento emitido quando alguém joga
     */
    event Jogo(address indexed jogador, bool resultado, uint256 timestamp);

    /**
     * @dev Simula um jogo de cara ou coroa
     * @return true = cara, false = coroa
     * 
     * Resultado é baseado em:
     * - block.timestamp (hora do bloco)
     * - msg.sender (seu endereço)
     * Qualquer um pode calcular o resultado antes de jogar!
     */
    function jogar() public returns (bool) {
        // Hash do timestamp + seu endereço
        bytes32 hash = keccak256(abi.encodePacked(block.timestamp, msg.sender));

        // Converte para número e tira o resto da divisão por 2
        // Resultado: 0 ou 1
        bool resultado = uint256(hash) % 2 == 0;

        emit Jogo(msg.sender, resultado, block.timestamp);

        return resultado;
    }

    /**
     * @dev Versão com número específico
     * @param numero Um número qualquer (seed)
     * @return true ou false
     */
    function jogarComNumero(uint256 numero) public returns (bool) {
        bytes32 hash = keccak256(abi.encodePacked(numero, msg.sender, block.timestamp));
        bool resultado = uint256(hash) % 2 == 0;

        emit Jogo(msg.sender, resultado, block.timestamp);

        return resultado;
    }

    /**
     * @dev Sorteia um número entre 1 e max
     * @param max O número máximo (inclusive)
     * @return Número sorteado
     */
    function sortearAte(uint256 max) public view returns (uint256) {
        require(max > 0, "Max deve ser maior que 0");

        bytes32 hash = keccak256(abi.encodePacked(block.timestamp, msg.sender));
        return (uint256(hash) % max) + 1;
    }
}

Como Testar no Remix

  1. Deploy no Remix VM
  2. Chame jogar() → retorna true ou false + emite evento
  3. Chame jogarComNumero(123) → resultado baseado na seed
  4. Chame sortearAte(10) → retorna número entre 1 e 10
  5. Tente sortearAte(0) → deve reverter

⚠️ Importante

Este não é randomness verdadeiro! Em produção: - A blockchain é determinística - Mineradores podem manipular block.timestamp - Qualquer um pode calcular o resultado antes de enviar a transação

Para randomness real, use: - Chainlink VRF - commit-reveal schemes - Oráculos externos

Use Case

Deixar a aula leve • Aprender sobre limitações de aleatoriedade em blockchain