# Secure Random Numbers

> Use Flare's secure randomness in your application.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

Source: https://dev.flare.network/network/guides/secure-random-numbers

This guide shows how to obtain secure, uniform random numbers on Flare. Secure randomness is generated by the [Scaling](/ftso/scaling/overview) protocol, where approximately 100 independent data providers generate local randomness every 90 seconds (a voting round), commit onchain, then reveal. The protocol aggregates these values into a final, uniformly distributed random number.

As long as **any one provider** generates an honest, hidden nnn\-bit random value, the sum modulo 2n2^n2n remains uniform. If manipulation is detected (e.g., a reveal omission), the round's `isSecure` flag is set to false, offenders are penalized, and their values are excluded for subsequent rounds.

<details>
<summary>Understand the secure random mechanism.</summary>

Understand the secure random mechanism.

As described in the [FTSOv2 whitepaper](/assets/files/20240223-FlareTimeSeriesOracleV2-4c7f9927c2e064c0ad5d606201e9cb59.pdf), the Scaling protocol consists of the following phases:

1.  **Commit:** During the Commit phase, data providers prepare their submissions for each of the data feeds and encode them into a 4-byte vector. Then, each data provider publishes on chain a hash commitment obtained as:
    
    `Hash(address, voting_epoch_id, random_number, price_data)`
    
    -   **Random Number**: This Commit includes a locally generated random number.
    -   **Purpose**: The random number blinds the Commit hash of the user from a search attack and is used later (once revealed) to contribute to onchain randomness.
2.  **Reveal:** During the Reveal phase, each data provider reveals all inputs to their hash commitment. As such, all locally produced random numbers become available onchain.
    
3.  **Signing:** After the Reveal phase, data providers perform a number of local computations relevant to the Scaling protocol, which include:
    
    -   Computing the weighted median prices
    -   Calculating the rewards
    
    All these are packaged into a Merkle root, which is published onchain together with a signature of the root.
    
4.  **Finalization:** Once enough signatures for the same Merkle root are gathered, the process is finalized.
    

**Secure Random Numbers**

For each voting round (90 seconds), let each provider's random value be ri∈\[0,2n−1\]r\_i \\in \[0, 2^n -1\]ri​∈\[0,2n−1\]. The voting round's random number is:

R\=(∑iri)mod  2nR = \\left( \\sum\_{i} r\_i \\right) \\mod{2^n}R\=(i∑​ri​)mod2n

Because commits are fixed before reveals, if any one rir\_iri​ is uniformly random and not chosen adaptively after seeing others, RRR is uniformly random over \[0,2n−1\]\[0, 2^n -1\]\[0,2n−1\].

</details>

## Use secure random onchain[​](#use-secure-random-onchain "Direct link to Use secure random onchain")

tip

You can integrate secure random numbers into your application on Flare for no cost.

SecureRandomConsumer.sol

```
// SPDX-License-Identifier: MITpragma solidity ^0.8.25;import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol";import {RandomNumberV2Interface} from "@flarenetwork/flare-periphery-contracts/coston2/RandomNumberV2Interface.sol";/** * @title SecureRandomConsumer * @notice Example consumer that reads secure random values from Flare's RandomNumberV2. * @dev THIS IS AN EXAMPLE CONTRACT. DO NOT USE THIS EXACT CODE IN PRODUCTION. */contract SecureRandomConsumer {    /**     * @notice Returns the latest secure random number.     * @dev The underlying provider returns `(uint256 random, bool isSecure, uint256 timestamp)`.     *      Only returns `random` when `isSecure == true`. This function is `view`.     * @return randomNumber Latest secure random value.     */    function getSecureRandomNumber()        external        view        returns (uint256 randomNumber, bool isSecure, uint256 timestamp)    {        RandomNumberV2Interface randomV2 = ContractRegistry.getRandomNumberV2();        (uint256 _randomNumber, bool _isSecure, uint256 _timestamp) = randomV2            .getRandomNumber();        // DO NOT USE returned value if isSecure==false. Wait until the next secure round.        require(isSecure, "Random number is not secure yet");        return (_randomNumber, _isSecure, _timestamp);    }    /**     * @notice Convenience read: returns raw tuple from the random provider.     * @return randomNumber Latest random value (may be insecure).     * @return isSecure Whether the value is considered secure by provider.     * @return timestamp Provider timestamp for the random value.     */    function peekRandomNumber()        external        view        returns (uint256 randomNumber, bool isSecure, uint256 timestamp)    {        RandomNumberV2Interface randomV2 = ContractRegistry.getRandomNumberV2();        (randomNumber, isSecure, timestamp) = randomV2.getRandomNumber();    }}
```

[Open in Remix](https://remix.ethereum.org/#url=https://github.com/flare-foundation/developer-hub/blob/main/examples/developer-hub-solidity/SecureRandomConsumer.sol&version=builtin&evmVersion=cancun&optimize=true&runs=200)

  

In addition to the `randomNumber` itself, two other variables are retrieved:

-   `isSecure`: A boolean flag indicating whether the random number was generated securely:
    
    -   **True**: All providers that committed also revealed, and every reveal matched its commit.
    -   **False**: at least one omission or mismatch occurred for the round. Offending providers are penalized and excluded for a number of future rounds; the voting round's randomness is flagged as unsafe.
-   `timestamp`: The UNIX timestamp marking the end of the voting round during which data was collected from data providers to generate the specific number. Each voting round lasts for a fixed 90-second window.
    

Set EVM Version to Cancun

-   **Using Remix:** Set EVM version to `cancun` under **Solidity Compiler** → **Advanced Configurations**.
    
-   **Using Hardhat or Foundry:** Set EVM version to `cancun` in [hardhat.config.ts](https://github.com/flare-foundation/flare-hardhat-starter/blob/master/hardhat.config.ts#L34) or [foundry.toml](https://github.com/flare-foundation/flare-foundry-starter/blob/master/foundry.toml).
    
-   **Using Standard Solidity JSON:** Set `"evmVersion": "cancun"` in `settings`.
    
-   **Using `solc`:** Add `--evm-version cancun` flag to your command.
    

### Example lottery application[​](#example-lottery-application "Direct link to Example lottery application")

This contract implements an example simple lottery system that utilizes a secure random number to select a winner. Participants can enter the lottery, and the winner is drawn using the secure random number generated by `RandomNumberV2`.

RandomNumberV2Lottery.sol

```
// SPDX-License-Identifier: MITpragma solidity >=0.7.6 <0.9.0;import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol";import {RandomNumberV2Interface} from "@flarenetwork/flare-periphery-contracts/coston2/RandomNumberV2Interface.sol";/** * THIS IS AN EXAMPLE CONTRACT. * DO NOT USE THIS CODE IN PRODUCTION. *//** * @title LotteryWithRandomNumber * @notice A lottery contract that utilizes a secure random number for determining winners. */contract LotteryWithRandomNumber {    address[] public participants;    uint256 public lotteryId;    uint256 public lotteryEndTimestamp;    // Event to log lottery results    event LotteryDrawn(        uint256 indexed lotteryId,        address winner,        uint256 randomNumber,        uint256 timestamp    );    /**     * @notice Enter the lottery.     * Participants can enter the lottery before it ends.     */    function enterLottery() external {        require(block.timestamp < lotteryEndTimestamp, "Lottery has ended");        participants.push(msg.sender);    }    /**     * @notice Start a new lottery round.     * This resets participants and sets the lottery end time.     * @param duration The duration of the lottery in seconds.     */    function startLottery(uint256 duration) external {        require(            participants.length == 0,            "Previous lottery must be concluded first"        );        lotteryId++;        lotteryEndTimestamp = block.timestamp + duration;    }    /**     * @notice Draw the winner of the lottery.     * Requires the lottery to be over and retrieves a secure random number to select the winner.     */    function drawLottery() external {        require(            block.timestamp >= lotteryEndTimestamp,            "Lottery is still ongoing"        );        require(participants.length > 0, "No participants in the lottery");        // Get the current random number and its properties        RandomNumberV2Interface randomNumberGenerator = ContractRegistry            .getRandomNumberV2();        (            uint256 randomNumber,            bool isSecureRandom,            uint256 randomTimestamp        ) = randomNumberGenerator.getRandomNumber();        // Use the random number to select a winner        uint256 winnerIndex = randomNumber % participants.length;        address winner = participants[winnerIndex];        // Emit the lottery result        emit LotteryDrawn(lotteryId, winner, randomNumber, randomTimestamp);        // Reset participants for the next lottery round        delete participants;    }    /**     * @notice Get the current number of participants.     * @return count The number of participants currently in the lottery.     */    function getParticipantCount() external view returns (uint256 count) {        return participants.length;    }    /**     * @notice Get the current lottery status.     * @return currentLotteryId The current lottery ID.     * @return endTimestamp The timestamp when the lottery ends.     */    function getLotteryStatus()        external        view        returns (uint256 currentLotteryId, uint256 endTimestamp)    {        return (lotteryId, lotteryEndTimestamp);    }}
```

[Open in Remix](https://remix.ethereum.org/#url=https://github.com/flare-foundation/developer-hub/blob/main/examples/developer-hub-solidity/RandomNumberV2Lottery.sol&version=builtin&evmVersion=cancun&optimize=true&runs=200)

  

## Use secure random offchain[​](#use-secure-random-offchain "Direct link to Use secure random offchain")

To obtain a secure random number offchain, you need two key pieces of information:

1.  **RPC Endpoint URL:** The RPC Endpoint URL determines which network your code will interact with. You can use a node provider service or point to your [own RPC node](/run-node#rpc-node). A comprehensive list of public and private RPC endpoints for all Flare networks is available on the [Network Configuration](/network/overview#configuration) page.
    
2.  **Contract Address:** The address for the `RandomNumberV2` contract varies by network. You can obtain this address in two ways:
    
    -   **From the Solidity Reference page:** Find the `RandomNumberV2` address for each network on the [Solidity Reference](/network/solidity-reference) page.
        
        **OR**
        
    -   **Query the FlareContractRegistry Contract:** The `FlareContractRegistry` contract has the same address across all networks. You can query it to get the `RandomNumberV2` contract address. Refer to the specific language guides for examples: - [JavaScript](/network/guides/flare-for-javascript-developers#make-query) - [Python](/network/guides/flare-for-python-developers#make-query) - [Rust](/network/guides/flare-for-rust-developers#make-query) - [Go](/network/guides/flare-for-go-developers#make-query)
        

Polling interval

The value updates every 90s (voting round). Poll no more than once per round or subscribe to the contract's update in your client.

This example uses [web3.js](https://github.com/web3/web3.js) to retrieve a secure random number on Flare Testnet Coston2.

```
npm install web3
```

secure\_random.js

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.import { Web3 } from "web3";// RandomNumberV2 address where the secure RNG is served (Flare Testnet Coston2)// See https://dev.flare.network/network/solidity-referenceconst ADDRESS = "0x5CdF9eAF3EB8b44fB696984a1420B56A7575D250";const RPC_URL = "https://coston2-api.flare.network/ext/C/rpc";// ABI for RandomNumberV2 contractconst ABI =  '[{"inputs":[{"internalType":"address","name":"_signingPolicySetter","type":"address"},{"internalType":"uint32","name":"_initialRewardEpochId","type":"uint32"},{"internalType":"uint32","name":"_startingVotingRoundIdForInitialRewardEpochId","type":"uint32"},{"internalType":"bytes32","name":"_initialSigningPolicyHash","type":"bytes32"},{"internalType":"uint8","name":"_randomNumberProtocolId","type":"uint8"},{"internalType":"uint32","name":"_firstVotingRoundStartTs","type":"uint32"},{"internalType":"uint8","name":"_votingEpochDurationSeconds","type":"uint8"},{"internalType":"uint32","name":"_firstRewardEpochStartVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"_rewardEpochDurationInVotingEpochs","type":"uint16"},{"internalType":"uint16","name":"_thresholdIncreaseBIPS","type":"uint16"},{"internalType":"uint32","name":"_messageFinalizationWindowInRewardEpochs","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"protocolId","type":"uint8"},{"indexed":true,"internalType":"uint32","name":"votingRoundId","type":"uint32"},{"indexed":false,"internalType":"bool","name":"isSecureRandom","type":"bool"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"ProtocolMessageRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"rewardEpochId","type":"uint24"},{"indexed":false,"internalType":"uint32","name":"startVotingRoundId","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"threshold","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"seed","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"voters","type":"address[]"},{"indexed":false,"internalType":"uint16[]","name":"weights","type":"uint16[]"},{"indexed":false,"internalType":"bytes","name":"signingPolicyBytes","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"timestamp","type":"uint64"}],"name":"SigningPolicyInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"SigningPolicyRelayed","type":"event"},{"inputs":[{"internalType":"uint256","name":"_protocolId","type":"uint256"},{"internalType":"uint256","name":"_votingRoundId","type":"uint256"}],"name":"getConfirmedMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRandomNumber","outputs":[{"internalType":"uint256","name":"_randomNumber","type":"uint256"},{"internalType":"bool","name":"_isSecureRandom","type":"bool"},{"internalType":"uint256","name":"_randomTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getVotingRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastInitializedRewardEpochData","outputs":[{"internalType":"uint32","name":"_lastInitializedRewardEpoch","type":"uint32"},{"internalType":"uint32","name":"_startingVotingRoundIdForLastInitializedRewardEpoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"protocolId","type":"uint256"},{"internalType":"uint256","name":"votingRoundId","type":"uint256"}],"name":"merkleRoots","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint24","name":"rewardEpochId","type":"uint24"},{"internalType":"uint32","name":"startVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"threshold","type":"uint16"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"address[]","name":"voters","type":"address[]"},{"internalType":"uint16[]","name":"weights","type":"uint16[]"}],"internalType":"struct IIRelay.SigningPolicy","name":"_signingPolicy","type":"tuple"}],"name":"setSigningPolicy","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signingPolicySetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"startingVotingRoundIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stateData","outputs":[{"internalType":"uint8","name":"randomNumberProtocolId","type":"uint8"},{"internalType":"uint32","name":"firstVotingRoundStartTs","type":"uint32"},{"internalType":"uint8","name":"votingEpochDurationSeconds","type":"uint8"},{"internalType":"uint32","name":"firstRewardEpochStartVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"rewardEpochDurationInVotingEpochs","type":"uint16"},{"internalType":"uint16","name":"thresholdIncreaseBIPS","type":"uint16"},{"internalType":"uint32","name":"randomVotingRoundId","type":"uint32"},{"internalType":"bool","name":"isSecureRandom","type":"bool"},{"internalType":"uint32","name":"lastInitializedRewardEpoch","type":"uint32"},{"internalType":"bool","name":"noSigningPolicyRelay","type":"bool"},{"internalType":"uint32","name":"messageFinalizationWindowInRewardEpochs","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"toSigningPolicyHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]';export async function main() {  // Connect to an RPC node  const w3 = new Web3(RPC_URL);  // Set up contract instance  const randomV2 = new w3.eth.Contract(JSON.parse(ABI), ADDRESS);  // Fetch secure random number  const res = await randomV2.methods.getRandomNumber().call();  // Log results  console.log("Random Number:", res["_randomNumber"]);  console.log("Is secure random:", res["_isSecureRandom"]);  console.log("Timestamp:", res["_randomTimestamp"]);  return res;}main();
```

This example uses [ethers.js](https://github.com/ethers-io/ethers.js/) to retrieve a secure random number on Flare Testnet Coston2.

```
npm install ethers
```

secure\_random.js

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.import { ethers } from "ethers";// RandomNumberV2 address where the secure RNG is served (Flare Testnet Coston2)// See https://dev.flare.network/network/solidity-referenceconst ADDRESS = "0x5CdF9eAF3EB8b44fB696984a1420B56A7575D250";const RPC_URL = "https://coston2-api.flare.network/ext/C/rpc";// ABI for RandomNumberV2 contractconst ABI =  '[{"inputs":[{"internalType":"address","name":"_signingPolicySetter","type":"address"},{"internalType":"uint32","name":"_initialRewardEpochId","type":"uint32"},{"internalType":"uint32","name":"_startingVotingRoundIdForInitialRewardEpochId","type":"uint32"},{"internalType":"bytes32","name":"_initialSigningPolicyHash","type":"bytes32"},{"internalType":"uint8","name":"_randomNumberProtocolId","type":"uint8"},{"internalType":"uint32","name":"_firstVotingRoundStartTs","type":"uint32"},{"internalType":"uint8","name":"_votingEpochDurationSeconds","type":"uint8"},{"internalType":"uint32","name":"_firstRewardEpochStartVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"_rewardEpochDurationInVotingEpochs","type":"uint16"},{"internalType":"uint16","name":"_thresholdIncreaseBIPS","type":"uint16"},{"internalType":"uint32","name":"_messageFinalizationWindowInRewardEpochs","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"protocolId","type":"uint8"},{"indexed":true,"internalType":"uint32","name":"votingRoundId","type":"uint32"},{"indexed":false,"internalType":"bool","name":"isSecureRandom","type":"bool"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"ProtocolMessageRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"rewardEpochId","type":"uint24"},{"indexed":false,"internalType":"uint32","name":"startVotingRoundId","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"threshold","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"seed","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"voters","type":"address[]"},{"indexed":false,"internalType":"uint16[]","name":"weights","type":"uint16[]"},{"indexed":false,"internalType":"bytes","name":"signingPolicyBytes","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"timestamp","type":"uint64"}],"name":"SigningPolicyInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"SigningPolicyRelayed","type":"event"},{"inputs":[{"internalType":"uint256","name":"_protocolId","type":"uint256"},{"internalType":"uint256","name":"_votingRoundId","type":"uint256"}],"name":"getConfirmedMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRandomNumber","outputs":[{"internalType":"uint256","name":"_randomNumber","type":"uint256"},{"internalType":"bool","name":"_isSecureRandom","type":"bool"},{"internalType":"uint256","name":"_randomTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getVotingRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastInitializedRewardEpochData","outputs":[{"internalType":"uint32","name":"_lastInitializedRewardEpoch","type":"uint32"},{"internalType":"uint32","name":"_startingVotingRoundIdForLastInitializedRewardEpoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"protocolId","type":"uint256"},{"internalType":"uint256","name":"votingRoundId","type":"uint256"}],"name":"merkleRoots","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint24","name":"rewardEpochId","type":"uint24"},{"internalType":"uint32","name":"startVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"threshold","type":"uint16"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"address[]","name":"voters","type":"address[]"},{"internalType":"uint16[]","name":"weights","type":"uint16[]"}],"internalType":"struct IIRelay.SigningPolicy","name":"_signingPolicy","type":"tuple"}],"name":"setSigningPolicy","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signingPolicySetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"startingVotingRoundIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stateData","outputs":[{"internalType":"uint8","name":"randomNumberProtocolId","type":"uint8"},{"internalType":"uint32","name":"firstVotingRoundStartTs","type":"uint32"},{"internalType":"uint8","name":"votingEpochDurationSeconds","type":"uint8"},{"internalType":"uint32","name":"firstRewardEpochStartVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"rewardEpochDurationInVotingEpochs","type":"uint16"},{"internalType":"uint16","name":"thresholdIncreaseBIPS","type":"uint16"},{"internalType":"uint32","name":"randomVotingRoundId","type":"uint32"},{"internalType":"bool","name":"isSecureRandom","type":"bool"},{"internalType":"uint32","name":"lastInitializedRewardEpoch","type":"uint32"},{"internalType":"bool","name":"noSigningPolicyRelay","type":"bool"},{"internalType":"uint32","name":"messageFinalizationWindowInRewardEpochs","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"toSigningPolicyHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]';export async function main() {  // Connect to an RPC node  const provider = new ethers.JsonRpcProvider(RPC_URL);  // Set up contract instance  const randomV2 = new ethers.Contract(ADDRESS, JSON.parse(ABI), provider);  // Fetch secure random number  const res = await randomV2.getRandomNumber();  // Log results  console.log("Random Number:", res[0]);  console.log("Is secure random:", res[1]);  console.log("Timestamp:", res[2]);  return res;}main();
```

This example uses [web3.py](https://github.com/ethereum/web3.py) to retrieve a secure random number on Flare Testnet Coston2.

```
uv add web3
```

```
pip install web3
```

secure\_random.py

```
# THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.import asynciofrom web3 import AsyncHTTPProvider, AsyncWeb3# RandomNumberV2 address where the secure RNG is served (Flare Testnet Coston2)# See https://dev.flare.network/network/solidity-referenceADDRESS = "0x5CdF9eAF3EB8b44fB696984a1420B56A7575D250"RPC_URL = "https://coston2-api.flare.network/ext/C/rpc"# ABI for RandomNumberV2 contractABI = '[{"inputs":[{"internalType":"address","name":"_signingPolicySetter","type":"address"},{"internalType":"uint32","name":"_initialRewardEpochId","type":"uint32"},{"internalType":"uint32","name":"_startingVotingRoundIdForInitialRewardEpochId","type":"uint32"},{"internalType":"bytes32","name":"_initialSigningPolicyHash","type":"bytes32"},{"internalType":"uint8","name":"_randomNumberProtocolId","type":"uint8"},{"internalType":"uint32","name":"_firstVotingRoundStartTs","type":"uint32"},{"internalType":"uint8","name":"_votingEpochDurationSeconds","type":"uint8"},{"internalType":"uint32","name":"_firstRewardEpochStartVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"_rewardEpochDurationInVotingEpochs","type":"uint16"},{"internalType":"uint16","name":"_thresholdIncreaseBIPS","type":"uint16"},{"internalType":"uint32","name":"_messageFinalizationWindowInRewardEpochs","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"protocolId","type":"uint8"},{"indexed":true,"internalType":"uint32","name":"votingRoundId","type":"uint32"},{"indexed":false,"internalType":"bool","name":"isSecureRandom","type":"bool"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"ProtocolMessageRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"rewardEpochId","type":"uint24"},{"indexed":false,"internalType":"uint32","name":"startVotingRoundId","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"threshold","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"seed","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"voters","type":"address[]"},{"indexed":false,"internalType":"uint16[]","name":"weights","type":"uint16[]"},{"indexed":false,"internalType":"bytes","name":"signingPolicyBytes","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"timestamp","type":"uint64"}],"name":"SigningPolicyInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"SigningPolicyRelayed","type":"event"},{"inputs":[{"internalType":"uint256","name":"_protocolId","type":"uint256"},{"internalType":"uint256","name":"_votingRoundId","type":"uint256"}],"name":"getConfirmedMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRandomNumber","outputs":[{"internalType":"uint256","name":"_randomNumber","type":"uint256"},{"internalType":"bool","name":"_isSecureRandom","type":"bool"},{"internalType":"uint256","name":"_randomTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getVotingRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastInitializedRewardEpochData","outputs":[{"internalType":"uint32","name":"_lastInitializedRewardEpoch","type":"uint32"},{"internalType":"uint32","name":"_startingVotingRoundIdForLastInitializedRewardEpoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"protocolId","type":"uint256"},{"internalType":"uint256","name":"votingRoundId","type":"uint256"}],"name":"merkleRoots","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint24","name":"rewardEpochId","type":"uint24"},{"internalType":"uint32","name":"startVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"threshold","type":"uint16"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"address[]","name":"voters","type":"address[]"},{"internalType":"uint16[]","name":"weights","type":"uint16[]"}],"internalType":"struct IIRelay.SigningPolicy","name":"_signingPolicy","type":"tuple"}],"name":"setSigningPolicy","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signingPolicySetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"startingVotingRoundIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stateData","outputs":[{"internalType":"uint8","name":"randomNumberProtocolId","type":"uint8"},{"internalType":"uint32","name":"firstVotingRoundStartTs","type":"uint32"},{"internalType":"uint8","name":"votingEpochDurationSeconds","type":"uint8"},{"internalType":"uint32","name":"firstRewardEpochStartVotingRoundId","type":"uint32"},{"internalType":"uint16","name":"rewardEpochDurationInVotingEpochs","type":"uint16"},{"internalType":"uint16","name":"thresholdIncreaseBIPS","type":"uint16"},{"internalType":"uint32","name":"randomVotingRoundId","type":"uint32"},{"internalType":"bool","name":"isSecureRandom","type":"bool"},{"internalType":"uint32","name":"lastInitializedRewardEpoch","type":"uint32"},{"internalType":"bool","name":"noSigningPolicyRelay","type":"bool"},{"internalType":"uint32","name":"messageFinalizationWindowInRewardEpochs","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardEpochId","type":"uint256"}],"name":"toSigningPolicyHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]'  # noqa: E501async def main() -> list[int, bool, int]:    # Connect to an RPC node    w3 = AsyncWeb3(        AsyncHTTPProvider(RPC_URL),    )    # Set up contract instance    random_v2 = w3.eth.contract(address=w3.to_checksum_address(ADDRESS), abi=ABI)    # Fetch secure random number    res = await random_v2.functions.getRandomNumber().call()    # Print results    print("Random Number:", res[0])    print("Is secure random:", res[1])    print("Timestamp:", res[2])    return resif __name__ == "__main__":    asyncio.run(main())
```

This example uses [alloy-rs](https://github.com/alloy-rs) to retrieve a secure random number on Flare Testnet Coston2.

```
cargo add alloy eyre tokio
```

secure\_random.rs

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.use alloy::{primitives::address, providers::ProviderBuilder, sol};use eyre::Result;sol!(    #[sol(rpc)]    RandomNumberV2,    "RandomNumberV2.json");#[tokio::main]async fn main() -> Result<()> {    // Relay address where the secure RNG is served (Flare Testnet Coston2)    // See https://dev.flare.network/network/solidity-reference    let random_v2_address = address!("97702e350CaEda540935d92aAf213307e9069784");    let rpc_url = "https://coston2-api.flare.network/ext/C/rpc".parse()?;    // Connect to an RPC node    let provider = ProviderBuilder::new().connect_http(rpc_url);    // Set up contract instance    let random_v2 = RandomNumberV2::new(random_v2_address, provider);    // Fetch secure random number    let RandomNumberV2::getRandomNumberReturn {        _randomNumber,        _isSecureRandom,        _randomTimestamp,    } = random_v2.getRandomNumber().call().await?;    // Print results    println!("Random Number: {_randomNumber:?}");    println!("Is secure random: {_isSecureRandom:?}");    println!("Timestamp: {_randomTimestamp:?}");    Ok(())}
```

This example uses the Go API from [Geth](https://geth.ethereum.org) to retrieve a secure random number on Flare Testnet Coston2.

```
go get github.com/ethereum/go-ethereum/ethclient
```

The project structure should look like:

```
developer-hub-go/├── coston2/│   └── *.go├── flare/│   └── *.go├── main.go├── go.mod└── go.sum
```

With Go, you need to manually fetch the contract's ABI and generate the Go bindings.

Look up the `RandomNumberV2` address by name via the [FlareContractRegistry](/network/guides/flare-contracts-registry) on your target network, then fetch the ABI from the routescan API for that address. For Coston2 (chain id 114) the route is `https://api.routescan.io/v2/network/testnet/evm/114/etherscan/api?module=contract&action=getabi&address=<random-number-v2-address>&format=raw`; for Flare mainnet use `https://api.routescan.io/v2/network/mainnet/evm/14/etherscan/api?...`. Save the response as `RandomNumberV2.abi` next to `go.mod` and generate the Go bindings with [abigen](https://geth.ethereum.org/docs/tools/abigen).

```
abigen --abi RandomNumberV2.abi --pkg coston2 --type RandomNumberV2 --out coston2/RandomNumberV2.go
```

coston2/secure\_random.go

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.package coston2import (	"context"	"fmt"	"math/big"	"github.com/ethereum/go-ethereum/accounts/abi/bind"	"github.com/ethereum/go-ethereum/common"	"github.com/ethereum/go-ethereum/ethclient")type RandomV2Response struct {	RandomNumber    *big.Int	IsSecureRandom  bool	RandomTimestamp *big.Int}func SecureRandom() *RandomV2Response {	// RandomNumberV2 address where the secure RNG is served (Flare Testnet Coston2)	// See https://dev.flare.network/network/solidity-reference	address := common.HexToAddress("0x5CdF9eAF3EB8b44fB696984a1420B56A7575D250")	rpcUrl := "https://coston2-api.flare.network/ext/C/rpc"	// Connect to an RPC node	client, _ := ethclient.Dial(rpcUrl)	// Set up contract instance	randomV2, _ := NewRandomNumberV2(address, client)	// Fetch secure random number	opts := &bind.CallOpts{Context: context.Background()}	res, _ := randomV2.GetRandomNumber(opts)	// Print results	fmt.Println("Random number: ", res.RandomNumber)	fmt.Println("Is secure random: ", res.IsSecureRandom)	fmt.Println("Timestamp: ", res.RandomTimestamp)	response := &RandomV2Response{		RandomNumber:    res.RandomNumber,		IsSecureRandom:  res.IsSecureRandom,		RandomTimestamp: res.RandomTimestamp,	}	return response}
```

## Watch the video[​](#watch-the-video "Direct link to Watch the video")
