- Ronin is an EVM protocol tailored for Web3 gaming, here used to build a meta racing game called Race the Ronin Chain.
- Players deposit $RON, predict parts of block hashes, and win if their predictions match the actual chain blocks over a 50-block race.
- Computation for determining winners is done off-chain for efficiency, with final results submitted on-chain by the contract owner.
- The mechanics showcase a blend of on-chain transparency and off-chain checks, making for a fun yet cost-effective Web3 game experiment.
Introduction
Ronin is an EVM protocol purpose-built to serve the unique needs of the gaming industry. Developed by Sky Mavis, the creators of Axie Infinity, Ronin stands out for its ability to support online games, specifically in the realm of Web3 gaming. A purpose-built blockchain protocol needs a purpose built blockchain game — and that’s what we created here. The game is called Race the Ronin Chain. Here is the full game repo on Chainstacklabs.NFP
Not for production (NFP) obviously. Feel free to take the source, modify to your needs, and boost the Web3 gaming ecosystem.We assume no responsibility for the code. Moreover, this is a very rough unaudited contract.- Anyone can create a race on the contract
- A race is a range of 50 blocks
- A number of players can enter the created race
- When entering a race, the players commit a up to 50 of 3-character hash values or slots called predictions
- The game mechanics is that if there’s a match of one of the committed 3-character values with a 64-character block hash in the range of 50 blocks race range, the player advances one step forward
- The player that advances the most by the end of the race (i.e. gets the most predictions right), wins
- There’s also other stuff like: when entering a race, each player pays the entrance fee of 1 RON; and the treasury keeps 1% on each win
Prerequisites
- Chainstack account to deploy a Ronin node.
- Foundry to compile, test, and deploy the contract.
- web3.py for the participation and the winner calculation & submission scripts.
Quick start
It’s all in the repository: race-ronin-chain.Solidity 0.8.19 & PUSH0
Keep the Solidity compiler to 0.8.19 unless the Ronin chain supports PUSH0 when you are reading this. Otherwise you won’t be able to deploy the contract.Generate the contract ABI
The one in the repository will work, but if you modify the contract, by far the easiest way to generate the ABI is to run:Deploy the contract
Ronin is not EIP-1559 compatible, so keep the transactions to legacy.- PRIVATE_KEY — your deployer private key. Important to remember that for the RaceRoninChain contract the message sender is the owner. This means that your will be submitting the race winner from this deployer account (see later in the article).
- TREASURY_ADDRESS — the house keeps 1% on each prize distribution, so this where the $RON will go from every race in your house fees.
Interact with the contract
There are two scripts in the repository in thepython_scripts
directory:
enter_race.py
— generates 50 random 3-character predictions for each of the players, starts a race, and enrols the four players in the racecompute_stats_and_submit_winner.py
— does the winner calculation and submits the winner
Game mechanics & other important considerations
There’s quite a bit of nuance to this seemingly simple game, so let’s do a run-down. Pretty sure there’s a lot of uncharted territory too. The game runs over a course of 50 blocks on the Ronin chain. Players try predicting parts of block hashes that will appear during this span. Each Ronin block comes with a unique hash—a 64-character hexadecimal string. The crux of the game is in forecasting these hash segments correctly. To participate, players commit to the game by executing a transaction to the contract’senterRace
function at a specified block number. This commitment not only signifies the start of a new race but also allows for a transparent view of the number of participants, the stakes involved in terms of total $RON, and the kickoff block.
When entering, players also submit their wager—the entry fee in $RON with up to 50 three-character predictions of the block hashes that will appear over the race duration.
As the race progresses, players’ positions are determined by how accurately their predictions match the actual block hashes within the race’s 50-block duration. A correct prediction, matching a segment of a block’s hash, propels a player forward in the race. Conversely, incorrect guesses leave a player lagging.
At the race’s conclusion, the game tallies each participant’s successful predictions against the block hashes that appeared during the race. The player whose predictions align most closely with the actual block hashes wins. In the event of a tie, the game honors the principle of “first come, first served”—the player who first submitted their predictions is declared the winner, rewarding promptness and deterring mimicry (but not front-running — more on that later).
Off-chain computation & other considerations
Off-chain compute
As I’m sure you noticed, the off-chain winner computation & submission is the most glaring thing about this game, so let’s explore it. Doing an on-chain computation is prohibitively expensive and is straight impossible at scale on any EVM network. This leaves us with the only option to move the winner compute to off-chain. Here’s the current implementation:- the
compute_stats_and_submit_winner.py
script runs and checks whether the latest race is completed - if completed, the script retrieves the block hashes for all 50 blocks from the start block to the end block of the race
- then the script calculates the winner based on the entered predictions and the actual block hashes
- the script submits the winner from the contract owner (the deployer)
- the contract does an on-chain verification of the submitted results and accepts or reverts the transaction. The verification is a check whether the submitted winning address & the full string of the submitted predictions are a part of the player and of this race id.