How to generate a random number in smart contract?

Julien Klepatch

Generating a random number in a smart contract is very useful, especially for games.

Can we do this in Solidity? Yes!

Here is the code:

pragma solidity ^0.6.0;

contract MyContract {
    function _randModulus(uint mod) internal returns(uint) {
        return uint(keccak256(abi.encodePacked(
            now, 
            block.difficulty, 
            msg.sender)
        )) % mod;
        nonce++;
        return rand;
    }
}

Let’s unpack everything!

First, we need a source of randomness, so we use

now, block.difficulty, msg.sender

Then we compute a hash of this – will be a bytes32 string like 0x89irwIRWOoo...:

keccak256(abi.encodePacked(
  now, 
  block.difficulty, 
  msg.sender
));

Then we cast this into an integer – this could be any (positive) integer, very small or very big:

uint(keccak256(abi.encodePacked(
  now, 
  block.difficulty, 
  msg.sender
)));

The final step is to use the modulo (%) operator to force this integer in a range:

uint(keccak256(abi.encodePacked(
  now, 
  block.difficulty, 
  msg.sender
))) % mod;

However, we have a problem…miners can manipulate now … Our random number is not safe to use…

We can fix this by importing a source of randomness outside of the control of the miner, by using an oracle (presumably controlled by someone we trust):

pragma solidity ^0.6.0;

contract Oracle {
    address admin;
    uint public rand;

    constructor() public {
        admin = msg.sender;
    }

    function feedRandomness(uint _rand) external {
        require(msg.sender == admin);
        rand = _rand;
    }
}

contract MyContract {
    Oracle oracle;
    uint nonce; //not strictly necessary

    constructor(address oracleAddress) public {
        oracle = Oracle(oracleAddress);
    }

    function foo() external {
        uint rand = _randModulus(10);
        //use rand however you want
    }

    function _randModulus(uint mod) internal returns(uint) {
        uint rand = uint(keccak256(abi.encodePacked(
            nonce,
            oracle.rand(),
            now, 
            block.difficulty, 
            msg.sender)
        )) % mod;
        nonce++;
        return rand;
    }
}

0 Comments

Leave a Reply

More great articles

Metamask explained in 2 mins

Metamask is the most popular wallet in crypto

But when you are a beginner, Metamask is NOT easy.

 In this article…

Read Story

Alternatives to web3.js

Web3.js is the leading client library for Ethereum. Personally, I am fine with it, but I know that some developers…

Read Story

EatTheBlocks Pro Subscription price increase 10 USD -> 15 USD

Disclaimer: the price increase will NOT affect existing users who subscribed before June 10th. If you are an existing subscriber…

Read Story

Never miss a minute

Get great content to your inbox every week. No spam.
[contact-form-7 id="6" title="Footer CTA Subscribe Form"]
Arrow-up