I'd like to introduce you to a simple stacking game written in Solidity and deployed on the Ethereum main network: [Day] Rings.
TL;DR Rules
Someone deposits a certain amount of Ether on the stack and for 5748 blocks anybody else can join in the game depositing the same amount. At the 5749th block, 98% of the Jackpot goes to the address that minimizes the value:
keccak256(blockhash(block_number_at_the_end_of_the_round) + player_address))
2% of the Jackpot goes to the house.
To play the game you need to install MetaMask.
Deployment specs
Transaction hash: 0x1a843…ef673587ca. Etherscan contract verification: submitted for verification on 2020-07-15.
Solidity code
You can check out the code: hashelot_dayrings_1.0.sol.
Comprehensive rules
The very first round of [Day] Rings starts when a player deposits his/her bet on the empty stack. The bet needs to be equal to or higher than 1 Finney (0.001 Ether).
From the moment his transaction - depositStack() call - is confirmed in a certain block X, the round goes on for 5748 additional blocks - stackWait=5748 -, during which any other player can take part in the bet and stack the exact same amount.
If a player tries to deposit a bet which is lower than the current value - stackValue -, said bet won’t be added to the stack and the value returned to the player.
If a player deposits a bet which is higher than the current stackValue a change will be returned to the player once the bet is added to the stack.
Once the (X+5749)th block has been mined, a winner can be declared, either calling closeBet() or starting a new round with depositStack(). The winner is the user whose address, concatenated with the blockhash of the first block after the last one for which it was possible to enter the bet and passed through the hash function keccak256 and converted to an unsigned value - uint - returns the lowest value, or in other code words:
uint(keccak256(abi.encodePacked(blockhash(stackTime + stackWait + 1), playerAddress)))
rolling playerAddress among the addresses of all the players who entered the bet to find the minimum.
The winner takes 98% of the stack.
2% of the stack goes to the owner, to finance research and development of (hopefully less frivolous) decentralized ventures.
The number of blocks, 5749, has been chosen as a prime number (out of pure mathematical fun) to make a round hypothetically last a day or so.
The owner of the hashelot_dayrings smart contract may declare a winner with dustStack(), but only if there are no ongoing bets.
Methods and variables
- stackValue - A public unsigned integer that shows the current value for entering the bet. Updated at every round.
- stackTime - A public unsigned integer that shows the block number at which the round has been started. Updated at every round.
- stackWait - A public unsigned integer set by the owner to 5748, once and for all.
- stackPlayers - A public array containing the addresses of the players currently involved in a round.
- stackSoFar - A public unsigned integer that shows the total amount of winnings so far.
- depositStack() - A public payable function anyone can call to enter (or start) a bet. When starting a new bet it closes a previous one for which a winner has not been declared yet.
- checkBalance() - A public function which returns the current balance of the smart contract address.
- checkPlayers() - A public function which returns the number of player currently involved in a round.
- closeBet() - A public payable function anyone can call to declare a bet if there are no more available blocks to play.
- dustStack() - A public payable function that only the owner can call to declare a winner of an ended round.