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

IPFS Explained: Add Decentralized Storage to Your Dapps

IPFS is a distributed system for storing and accessing files, websites, applications, and data. IPFS allows users to host and…

Read Story

Weekly Blockchain News, 28th Feb

Ethereum (L1/L2) Ether saw a slight fluctuation in value and is currently at $2600. Ethereum community member called out Coinbase…

Read Story

100+ video tutorials on Ethereum / Solidity development

EatTheBlocks Pro just reached a new milestone: there are now more than 100 videos on Ethereum & Solidity development. That's…

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