Smart contracts on Ethereum often rely on block.timestamp for time-sensitive functions such as auctions, lotteries, and token vesting. However, block.timestamp is not entirely immutable because it can be adjusted slightly by the miner who mines the block, within a window of approximately 15 seconds according to Ethereum protocol implementations. This creates a vulnerability where a miner could manipulate the timestamp to their advantage. For instance, in a decentralized auction, a miner who is also a bidder could alter the timestamp to prematurely end the auction when they are the highest bidder, thereby securing an unfair win.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract DiceRoll {
uint256 public lastBlockTime;
constructor() payable {}
function rollDice() external payable {
require(msg.value == 5 ether, "Must send 5 ether to play"); // Player must send 5 ether to play
require(block.timestamp != lastBlockTime, "Only 1 transaction per block allowed"); // Ensures only 1 transaction per block
lastBlockTime = block.timestamp;
// Player wins if the last digit of the block timestamp is less than 5
if (block.timestamp % 10 < 5) {
(bool sent,) = msg.sender.call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
}
}