Build On-Chain Games: A Breakdown of the Guessing Game on TEN

Jobin Babu Ayathil
Obscuro Labs
Published in
5 min readJul 26, 2024

Introduction

In this blog, we’ll delve into a simple Guessing Game — and explore why it’s only possible on TEN by highlighting specific contract code snippets and key features. By the end, you will also have learnt how to build on-chain games with private states and secure randomness.

Blockchain technology is continuously evolving, introducing new paradigms that extend what’s possible. One such advancement is TEN, which provides a distinct environment for creating decentralized applications (DApps) with added Encryption and confidentiality features. In the realm of on-chain gaming, addressing the challenges and improving upon existing frameworks is crucial. For an in-depth discussion on the current challenges, you can read “The Open Problems of Onchain Games” by Paradigm here.

The Guessing Game: A Quick Overview

The Guessing Game is a simple yet intriguing DApp where players guess a secret number to win Ether (ETH). What makes this game special is its reliance on TEN’s encryption, confidentiality features, and on-chain random number generation.

Before you continue reading, go and play the Guessing Game here. Try your best to crack it in any way possible, even attempt to cheat. If you can succeed, feel free to trash this blog. But if you can’t, come back and read on to see how we made it possible and how you can too.

For those interested in the technical details, you can check out the actual Guessing Game contract on GitHub here.

Here’s a snapshot of how the game works:

  • Random Number Generation: The secret number is randomly generated and stored securely.
  • Confidentiality of Guesses: Players’ guesses and the corresponding game events are kept confidential.
  • Secure State Management: The state changes in the contract, including secret numbers and guesses, are encrypted and inaccessible to others.

Why TEN Makes the Guessing Game Unique

1. Unpredictable and Secure RNG

On TEN: The secret number is generated using a secure and unpredictable random number generator. This ensures fairness and security, as the number cannot be predicted or manipulated.

function _resetSecretNumber() private {
if (resetCount > 0) {
lastSecretNumber = secretNumber;
}
uint256 randomNumber = block.difficulty; // This opcode is secure on TEN
secretNumber = (randomNumber % MAX_GUESS) + 1;
lastResetTime = block.timestamp;
resetCount += 1;
}

This snippet demonstrates the secret number reset, leveraging block difficulty for RNG. On TEN, this would be secure due to encrypted mempool and secure enclaves.

On Ethereum: Using block.difficulty or block.prevrandao for randomness is insecure because miners can manipulate these values. This predictability makes the RNG vulnerable to attacks.

The on-chain RNG that TEN provides is secure, free, and easily accessible. This could be a game changer for building casino or gambling games, which require a secure yet verifiable source of randomness. With TEN, developers don’t need to rely on external sources like Chainlink’s VRF that are transparent and unsuitable for games, as secure randomness is just an opcode away. This significantly simplifies the development process of games in Web3.

For those who want to dive deeper into the randomness on TEN, you can check out this blog.

2. Confidential States

On TEN: The contract ensures that the secret number and players’ guesses remain confidential. TEN’s encryption features block direct access to storage i.e getStorageAt doesn’t work, ensuring that confidential states can only be accessed through designated functions.

mapping(address => uint256) private lastGuess;
mapping(address => uint256) private lastDifference;
function getLastGuess() external view returns (uint256) {
require(msg.sender == tx.origin, “Only the user can access their last guess”);
return lastGuess[msg.sender];
}

These mappings track player guesses and differences confidentially, and access control is implemented to ensure confidentiality.

On Ethereum: Although states can be marked as private, they can still be accessed using getStorageAt calls, making true confidentiality unachievable.

The same confidential shared states could be used to build games with hidden maps, levels, surprises, and more. For example, imagine a blockchain-based version of a treasure hunt game like “Legend of Zelda” where the map and treasure locations remain hidden until discovered by the player. This adds an element of surprise and excitement, as players cannot predict or see the game’s secrets until they encounter them.

3. Invisible Transactions

On TEN: Transactions related to the Guessing Game, including guesses and state changes, are invisible to others. This ensures that no one can see the guesses or state changes, preserving the game’s fairness.

event Guessed(address indexed user, uint256 guessedNumber, bool success, string feedback);
function guess(uint256 _number) external payable {
// logic for guessing
emit Guessed(msg.sender, _number, false, feedback);
}

The Guessed event and guess function handles user guesses. On TEN, these events and transactions would remain confidential.

On Ethereum: All transactions and events are publicly visible on the blockchain. This transparency could allow players to gain unfair advantages by observing others’ actions.

Invisible transactions can be incredibly useful in various gaming scenarios. For example, consider a blockchain-based board game similar to “Clue.” Players make moves, collect clues, and deduce the mystery. The transactions for these actions remain invisible, ensuring that opponents cannot see the moves and clues collected by other players. This enhances the strategic depth and excitement of the game, as players must rely on their skills and strategies rather than on-chain visibility.

4. Events

On TEN: Events can be made confidential by including an address in the parameters. If no address is included, the event remains public.

event PrivateGuessed(address indexed user, uint256 guessedNumber, bool success, string feedback);
function privateGuess(uint256 _number) external payable {
// logic for guessing
emit PrivateGuessed(msg.sender, _number, false, feedback);
}

This event is confidential to the address msg.sender, ensuring that only the intended recipient can view it.

For geeks who want to go into detail on how private or public events on TEN work, you can check out the detailed events design here.

Bonus: Programmable Encryption and Access Control

On TEN: Developers can choose which aspects of their contract are confidential or public. Access control can be added to functions to restrict data visibility to authorized users only.

mapping(address => uint256) private userSecretData;
function storeSecretData(uint256 _data) external {
userSecretData[msg.sender] = _data;
}
function retrieveSecretData() external view returns (uint256) {
require(userSecretData[msg.sender] != 0, “No data stored by this user”);
return userSecretData[msg.sender];
}

This function allows users to store and retrieve their data securely, ensuring confidentiality and controlled access. Note: This snippet is a bonus example and not part of the Guessing Game.

Conclusion

The Guessing Game on TEN exemplifies how blockchain technology can innovate traditional gaming concepts by integrating encryption and confidentiality features. TEN’s unique capabilities ensure an anti-cheat and confidential gaming experience, setting a new standard for Web3 game development & propelling fully on-chain games forward.

If you want to start building fully on-chain games, then get started here.

Website | Whitepaper | Litepaper | Twitter | Discord

--

--