Rings - A simple stacking game

If you like it, then you shoulda put a ring on it.

Rings is a stacking game written in Solidity and deployed on the Ethereum main network, whose game play you can audit straight out of the blockchain. The contract has been verified on Etherscan on 2020-06-06.

You may also test it out on Ropsten.



TL;DR Rules

Someone deposits a certain amount of Ether on the stack and for 126 blocks anybody else can join in the game depositing the same amount. At the 127th 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% goes to the house.

Rules

The very first round of Rings starts when a player deposits his 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 126 additional blocks - stackWait=126 -, 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+127)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, 127, has been chosen as a prime number (out of pure mathematical fun) to make a round hypothetically last around half an hour.

The owner of the hashelot_rings smart contract may declare a winner with dustStack(), but only if there are no ongoing bets.

Deployment specs

Transaction hash: 0x8c265…fc5a71971d. Etherscan contract verification: submitted for verification on 2020-06-06.

Rings v.1.1 release notes (2020-06-06)
  • Fixed vulnerability of last playable block.
  • Code verified on Etherscan.io.
  • Added control for preventing a player to enter a round twice.
  • Added MIT License.
Solidity code

You can check out the code: hashelot_rings_1.1.sol.

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 126, 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.