ThunderCore
ThunderCoreThunderCore Bridge
  • ⚡Hello world
  • Developer Program
  • Network Details
    • ThunderCore Mainnet
    • ThunderCore Testnet
    • Token List
    • Smart Contract Services
    • Full Node Deployment
  • Develop on ThunderCore
    • Migrate from Ethereum
    • Using Foundry
    • Using Hardhat
    • Using Remix
    • Using Truffle
    • Deploy TT20
    • Deploy a DApp
    • Deploy a NFT
  • Develop on TT Wallet
    • DApp Submission
    • Deeplinking
    • Signing Messages
    • Ethereum Provider API
    • Token Listing
    • Advertising with TT Wallet
      • Logo size submission guideline
      • Promotional Package
      • How we help developers
    • Developer Build - TT Wallet (Android)
  • FAQs
  • Product / Protocol
    • Wallets
      • MetaMask
        • Create a MetaMask Wallet
        • Create multiple accounts
      • TT Wallet
    • ThunderCore Bridge
      • Architecture
      • Ethereum <> ThunderCore
      • BNB chain <> ThunderCore
      • Interact with ThunderCore Bridge
  • Tool
    • Game Development
      • MetaFab
    • DApp Development
      • Faucet
      • Random Number Generator
      • Oracles
      • Referral Library
      • TTSwap Resources
      • Wrapped TT Addresses
      • Multicall
      • Subgraph
      • Auth Service
      • Wallet Service
      • Node Service
Powered by GitBook
On this page
  1. Tool
  2. DApp Development

Random Number Generator

Summary

The ThunderCore blockchain supports generating cryptographically secure 256-bit random numbers through a Thunder trusted random number generating pre-compiled contract.

Motivation

When developing smart contracts for Ethereum, developers do not have built-in support for generating cryptographically secure random numbers. While there are some possible solutions (e.g. using Ethereum Alarm r Oraclize), these solutions often rely on external services and are not scalable. To address this need, ThunderCore has implemented built-in support to generate cryptographically secure random numbers through a pre-compiled contract.

Specification ThunderCore has implemented a pre-compiled contract which resides at address 0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7. This address is the first 20 bytes of sha256("Thunder_Random"). Each invocation of fallback function of trusted random generator precompiled contract will return a 256-bit random number. The gas cost for each invocation is 1265040. Below is an example which can be embedded into a smart contract. ThunderCore also provides a library which can be sued in Remix with import "github.com/thundercore/RandomLibrary/RandomInterface.sol from Github with URL in Remix. The random number generator will always return a bytes32 value, so you will need to cast or convert this value as it suits your needs.

interface ThunderRandomLibraryInterface {
    function rand() external returns (uint256);
}

Example In the basic example shown below, a random number is used to determine whether the contract will pay the user. If the number is greater than the bet from the user, the contract takes the user's wager. If not, the contract pays the user their own bet plus 1.

Note: the require(msg.sender == tx.origin) check in bet() is necessary for security and explained below.

pragma solidity ^0.8.9;

interface ThunderRandomLibraryInterface {
    function rand() external returns (uint256);
}

contract RandomExampleInterfaceVersion {
    event didWin(bool);
    uint256 public contractBalance;
    // Random precompiled contract address is 0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7
    address constant public randomNumberContractAddress = 0x8cC9C2e145d3AA946502964B1B69CE3cD066A9C7; 
    ThunderRandomLibraryInterface internal RNGLibrary;

    constructor() payable {
        contractBalance = uint256(msg.value);
        RNGLibrary = ThunderRandomLibraryInterface(randomNumberContractAddress);
    }

    function betNumber(uint256 bet) payable external returns (bool) {
        // block calls from other contracts to prevent "revert transaction unless I won" attacks
        require(msg.sender == tx.origin);
        
        if (msg.value < 5) {
            contractBalance = contractBalance + msg.value;

            emit didWin(false);
            return false;
        }

        uint256 randomNumber = RNGLibrary.rand();
        address payable sender = payable(msg.sender);
        if (bet < randomNumber) {
            sender.transfer(msg.value+1);
            emit didWin(true);

            contractBalance = contractBalance - 1;
            return true;
        }

        contractBalance = contractBalance + msg.value;
        emit didWin(false);
        return false;
    }
}

How to prevent Revert the Transaction Unless I Won attacks There's a conceptually simple approach to attack any game of chance on EVM compatible blockchains. The attacker would deploy a contract and do something like:

  1. Play a game of chance

  2. Check if the balance in the attacker's contract decreased after the game

  3. Revert the transaction if the contract balance decreased

In Solidity, the attack would look like this:

    function attack(uint256 v) public  {
        uint256 pool = this.balance;
        /* play game of chance ... */
        require(this.balance >= pool);
    }
  • msg.sender (address): sender of the message (current call)

  • tx.origin (address): sender of the transaction (full call chain)

Last updated 1 year ago

Add a require(msg.sender == tx.origin) check at the beginning of your bet function prevents other contracts from calling your own and thus blocks the attack. See the section in for details:

Block and Transaction Properties
Solidity in Depth