LogoLogo
WebsiteDiscordTelegramTwitter
  • 🏠Witnet Oracle Docs
  • Introduction
    • ❓What is Witnet?
      • ⚙️Oracle Architecture
      • 🪙The Witnet Coin (Wit)
      • 👛Wallets
      • 🤔Frequently Asked Questions
      • 😎Awesome Witnet
    • 🚀Quick Tutorials
      • 📈Price Feeds
      • 🎲Randomness
      • 🌐APIs and HTTP GET/POST
      • ⛏️Mining Wit
  • Smart contracts developers
    • ⛓️Supported chains
    • 🔮Wit/Oracle
      • HTTP GET Requests in Solidity
      • HTTP POST Requests in Solidity
      • Query GraphQL APIs in Solidity
      • Dynamic Requests in Solidity
      • UsingWitnet Inheritance
      • API Reference
        • Solidity API
          • Solidity Contracts
            • WitnetRequestBoard
        • Javascript API
        • RADON API
          • RADON Type System
          • RADON Errors
      • Multi-chain Addresses
    • 💹Wit/Price Feeds
      • How To Use Witnet Price Feeds
      • Update Conditions
      • Code Examples
      • API Reference
      • Multi-chain Addresses
        • Arbitrum Price Feeds
        • Avalanche Price Feeds
        • Base Price Feeds
        • Boba Price Feeds
        • Celo Price Feeds
        • Conflux Price Feeds
        • Cronos Price Feeds
        • Dogechain Price Feeds
        • Elastos Price Feeds
        • Ethereum Price Feeds
        • Gnosis Chain Price Feeds
        • Kaia Price Feeds
        • Kava Price Feeds
        • KCC Price Feeds
        • Mantle Price Feeds
        • Meter Price Feeds
        • Metis Price Feeds
        • Moonbeam Price Feeds
        • OKX Price Feeds
        • Optimism Price Feeds
        • Polygon Price Feeds
        • Reef Price Feeds
        • Scroll Price Feeds
        • Syscoin Price Feeds
        • Ultron Price Feeds
        • Request new price feed or chain support
    • 🎲Wit/Randomness
      • Generating Randomness
      • WitnetRandomness Contract
      • Low-level Requests
      • Code Examples
      • API Reference
      • Multi-chain Addresses
    • 🏗️Guides
      • 📖Solidity Contracts
        • Appliances
          • 📃WitnetPriceFeeds
          • 📃WitnetRandomness
        • Core
          • 📃WitnetOracle
          • 📃WitnetRadonRegistry
          • 📃WitnetRequest
          • 📃WitnetRequestFactory
          • 📃WitnetRequestTemplate
        • Mockups
          • 📃UsingWitnet
          • 📃UsingWitnetRandomness
          • 📃UsingWitnetRequest
          • 📃UsingWitnetRequestTemplate
          • 📃WitnetRandomnessRequestConsumer
          • 📃WitnetRequestConsumer
          • 📃WitnetRequestTemplateConsumer
      • 🧙Solidity Wizard
    • 🎓Tutorials
      • Building a Satoshi/Wei custom price feed
  • Witnet Node Operators
    • 🖥️Requirements
    • 🚀Witnet Node Quick Start Guide (Docker)
    • 🔎Next steps
    • 📄CLI Reference
    • 🤓Advanced Setups
      • Run Witnet as a systemd service
      • Run Witnet as a docker compose service
      • Paranoid mode (Witnet over proxies and Tor)
      • Configuration file
  • Witnet Node Developers
    • 🏗️Integration Guide
      • Node API Reference
      • Wallet API Reference
    • 🗜️Compile witnet-rust from Source Code
Powered by GitBook
On this page
  • Example 1: Bare Minimal
  • Example 2: Roll a die!
  • Example 3: Random Bytes
  • Example 4: Post a low-level hardcoded randomness request
  • Example 5: Clone a pre-deployed WitnetRequestRandomness contract

Was this helpful?

Edit on GitHub
  1. Smart contracts developers
  2. Wit/Randomness

Code Examples

PreviousLow-level RequestsNextAPI Reference

Last updated 1 year ago

Was this helpful?

Example 1: Bare Minimal

On each of the there is an instance of the WitnetRandomness contract that exposes the main randomness oracle functionality through a very simple interface.

The best way to interact with the WitnetRandomness contract is through the IWitnetRandomness interface, which is readily available in the .

This very basic example shows how easy is to source random uint32 values into your own contracts:

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "witnet-solidity-bridge/contracts/interfaces/IWitnetRandomness.sol";

contract MyContract {

    uint32 public randomness;
    uint256 public latestRandomizingBlock;
    IWitnetRandomness immutable public witnet;
    
    /// @param _witnetRandomness Address of the WitnetRandomness contract.
    constructor (IWitnetRandomness _witnetRandomness) {
        assert(address(_witnetRandomness) != address(0));
        witnet = _witnetRandomness;
    }
    
    receive () external payable {}

    function requestRandomNumber() external payable {
        latestRandomizingBlock = block.number;
        uint _usedFunds = witnet.randomize{ value: msg.value }();
        if (_usedFunds < msg.value) {
            payable(msg.sender).transfer(msg.value - _usedFunds);
        }
    }
    
    function fetchRandomNumber() external {
        assert(latestRandomizingBlock > 0);
        randomness = witnet.random(type(uint32).max, 0, latestRandomizingBlock);
    }
}

Two-step Generation of Randomness

This example follows a very common workflow for many randomness use cases: first you need to take note of the current block number and ask the WitnetRandomness to reseed itself, then, at a later time, you will be retrieving a random number that is derived from the random seed that was generated as a response to your former request.

This 2-step process preserves unpredictability of the random numbers that you get because it guarantees that the number is derived from a seed that was generated only after the request was sent.

Range of the Random Numbers

This example is generating random numbers in the range [0, 4294967296), but you can narrow that range down at will through the first argument of the witnet.random function:

fromZeroToNine = witnet.random(10, 0, latestRandomizingBlock);

As witnet.random always assumes that the range starts with 0, you can use an addition to offset the range. For example, to make it [1, 12]:

month = 1 + witnet.random(12, 0, latestRandomizingBlock);

And for [-100, 100]:

temperature = -100 + witnet.random(201, 0, latestRandomizingBlock);

Take into account that this example implements an asynchronous workflow — calling fetchRandomNumber() right after requestRandomNumber() will most likely cause the transaction to revert. Please allow 5-10 minutes for the randomization request to complete.

Example 2: Roll a die!

This example is doing something slightly more interesting: it simulates a dice game in which you need to pick a certain number, and then, after rolling the die, you will see if you guessed correctly what the lucky number would be:

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "witnet-solidity-bridge/contracts/interfaces/IWitnetRandomness.sol";

contract DieContract {

    uint32 sides;
    struct Guess {
        uint32 guessedNumber;
        uint256 blockHeight;
    }
    mapping (address => Guess) public guesses;
    IWitnetRandomness immutable public witnet;
    
    event Right(string message);
    event Wrong(string message);

    /// @param _witnetRandomness Address of the WitnetRandomness contract.
    constructor (IWitnetRandomness _witnetRandomness, uint32 _sides) {
        assert(address(_witnetRandomness) != address(0));
        witnet = _witnetRandomness;
        sides = _sides;
    }
    
    receive () external payable {}

    function guessNumber(uint32 _number) external payable {
        assert(_number > 0);
        assert(_number <= sides);
        assert(guesses[msg.sender].guessedNumber == 0);

        guesses[msg.sender].guessedNumber = _number;
        guesses[msg.sender].blockNumber = block.number;
        
        uint _usedFunds = witnet.randomize{ value: msg.value }();
        if (_usedFunds < msg.value) {
            payable(msg.sender).transfer(msg.value - _usedFunds);
        }
    }

    function roll() external {
        assert(guesses[msg.sender].guessedNumber != 0);
        
        uint32 luckyNumber = 1 + witnet.random(
            sides,
            0,
            guesses[msg.sender].blockNumber
        );
        
        if (luckyNumber == guesses[msg.sender].guessedNumber) {
            emit Right("Congratulations! You guessed the right number!");
        } else {
            emit Wrong("Sorry! You didn't guess the right number!");
        }
        
        guesses[msg.sender].guessedNumber = 0;
    }    
}

As this example allows multiple users to play the dice game at the same time, a mapping (address => Guess) is used to separately track everyone's choice of numbers and the block in which they placed their guess. In this way, you can make sure that every roll of the die is only affecting guesses that were placed at least 1 block in advance, and that further rolls of the die will not affect the outcome of past guesses.

Take into account that this example implements an asynchronous workflow — calling fulfillRandomness() right after getRandomNumber() will most likely cause the transaction to revert. Please allow 5-10 minutes for the randomization request to complete.

Example 3: Random Bytes

In addition to random numbers, the Witnet randomness oracle can also generate random sequences of bytes. Namely, these have the bytes32 type in Solidity:

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "witnet-solidity-bridge/contracts/interfaces/IWitnetRandomness.sol";

contract MyContract {

    bytes32 public randomness;
    uint256 public latestRandomizingBlock;
    IWitnetRandomness immutable public witnet;
    
    /// @param _witnetRandomness Address of the WitnetRandomness contract.
    constructor (IWitnetRandomness _witnetRandomness) {
        assert(address(_witnetRandomness) != address(0));
        witnet = _witnetRandomness;
    }
    
    receive () external payable {}

    function requestRandomness() external payable {
        latestRandomizingBlock = block.number;
        uint _usedFunds = witnet.randomize{ value: msg.value }();
        if (_usedFunds < msg.value) {
            payable(msg.sender).transfer(msg.value - _usedFunds);
        }
    }
    
    function fetchRandomness() external {
        assert(latestRandomizingBlock > 0);
        randomness = witnet.getRandomnessAfter(latestRandomizingBlock);
    }
    
}
randomness = witnet.getRandomnessAfter(latestRandomizingBlock);

Generating random bytes is specially interesting for many NFT use cases in which you need to assign attributes and traits at random to each of the item in a colllection. By sourcing 32 random bytes at once, you can use each of the bytes to affect the different traits that you want to assign.

Take into account that this example implements an asynchronous workflow — calling fetchRandomness() right after requestRandomness() will most likely cause the transaction to revert. Please allow 5-10 minutes for the randomization request to complete.

Example 4: Post a low-level hardcoded randomness request

pragma solidity ^0.8.0;

import "witnet-solidity-bridge/contracts/UsingWitnet.sol";
import "witnet-solidity-bridge/contracts/requests/WitnetRequest.sol";

import "@openzeppelin/contracts/access/Ownable.sol";  

contract MyContract
  is
    Ownable,
    UsingWitnet
{
  /// @dev Low-level Witnet Data Request composed on construction.
  IWitnetRequest public witnetRequest;
  
  /// @dev Randomness value eventually fetched from the Witnet oracle.
  bytes32 public witnetRandomness;

  /// @dev Unique identifier for the latest request posted to the Witnet Request Board.
  uint256 public witnetQueryId;    

  enum Status {
    Playing,
    Randomizing,
    Awarding
  }

  modifier inStatus(Status _status) {
    require(status() == _status, "bad mood");
  }

  constructor(WitnetRequestBoard _witnet)
    UsingWitnet(_witnet)
  {
    // Compose low-level Witnet data request bytecode,
    // that will be eventually posted to the Witnet side-chain
    // when calling to _witnetPostRequest(witnetRequest)
    witnetRequest = new WitnetRequest(
      hex"0a0f120508021a01801a0210022202100b10e807180a200a2833308094ebdc03"
    );
    /// @dev Witnet Data Request decoded as:
    ///
    /// {
    ///    "retrieve": [
    ///      {
    ///        "kind": "RNG",
    ///        "url": "",
    ///        "script": []
    ///      }
    ///    ],
    ///    "aggregate": {
    ///      "filters": [],
    ///      "reducer": 2
    ///    },
    ///    "tally": {
    ///      "filters": [],
    ///      "reducer": 11
    ///    }
    /// }
    ///
  }

  /// @dev Calculate current status.
  function status() public view returns (Status) {
    if (witnetRandomness != bytes32(0)) {
      return Status.Awarding;
    } else if (witnetQueryId > 0) {
      return Status.Randomizing;
    } else {
      return Status.Playing;
    }
  }

  /// @dev Pass from 'Playing' to 'Randomizing' status
  function stopPlaying()
      external payable
      onlyOwner
      inStatus(Status.Playing)
  {
    // Use internal method inherited from UsingWitnet, as to send the low-level randomness 
    // request to the WitnetRequestBoard instance. `msg.value` needs to be high enough as
    // to cover for `_witnetReward`
    uint256 _witnetReward;
    (witnetQueryId, _witnetReward) = _witnetPostRequest(witnetRequest);

    // Transfer back unused funds:
    if (msg.value > _witnetReward) {
      payable(msg.sender).transfer(msg.value - _witnetReward);
    }
  }

  /// @dev Pass from 'Randomizing' to either 'Awarding' or 'Playing' status, depending
  /// @dev on whether the randomness request was solved, or reverted, respectively.
  function startAwarding()
    external
    inStatus(Status.Randomizing)
  {
    uint _queryId = witnetQueryId;

    // Use internal method inherited from UsingWitnet, as to check whether the randomness
    // request has already been reported:
    require(_witnetCheckResultAvailability(_queryId), "not yet reported");

    // Low-level interaction with the WitnetRequestBoard as to deserialize the result,
    // and check whether the randomness request failed or succeeded:
    Witnet.Result memory _result = witnet.readResponseResult(_queryId);
    if (_result.success) {
      witnetRandomness = witnet.asBytes32(_result);
    } else {
      // step back to 'Playing' status:
      witnetQueryId = 0;
    }
  }

  /// ...
}

Example 5: Clone a pre-deployed WitnetRequestRandomness contract

contract MyContract {
  WitnetRequestRandomness public witnetRequest;
  contructor(WitnetRandomness _witnet) {
    witnetRequest = WitnetRequestRandomness(address(
      _witnet.witnetRandomnessRequest().clone()
    ));
    // witnetRequest is now owned by `msg.sender`
  }
  // ...
}

As you can see, this example is very similar to the above. The requestRandomness() function works the same as requestRandomNumber() above, but fetchRandomness() however uses the lower-level witnet.getRandomnessAfter() function to read the underlying random bytes instead of trying to derive a random integer from those:

🎲
EVM compatible chains supported by Witnet
witnet-solidity-bridge npm package
Example 1