# VRF V2 Best Practices
Source: https://docs.chain.link/vrf/v2/best-practices

> For the complete documentation index, see [llms.txt](/llms.txt).

> **TIP: VRF V2.5 Best Practices**
>
> Refer to the [VRF V2.5 Best Practices page](/vrf/v2-5/best-practices) for VRF best practices with updated VRF 2.5 code
> examples.

These are example best practices for using Chainlink VRF. To explore more applications of VRF, refer to our [blog](https://blog.chain.link/).

## Getting a random number within a range

If you need to generate a random number within a given range, use [modulo](https://docs.soliditylang.org/en/v0.8.7/types.html#modulo) to define the limits of your range. Below you can see how to get a random number in a range from 1 to 50.

```solidity
function fulfillRandomWords(
  uint256, /* requestId */
  uint256[] memory randomWords
) internal override {
  // Assuming only one random word was requested.
  s_randomRange = (randomWords[0] % 50) + 1;
}

```

## Getting multiple random values

If you want to get multiple random values from a single VRF request, you can request this directly with the `numWords` argument:

- If you are using the VRF v2 subscription method, see the [Get a Random Number](/vrf/v2/subscription/examples/get-a-random-number) guide for an example where one request returns multiple random values.
- If you are using the VRF v2 direct funding method, see the [Get a Random Number](/vrf/v2/direct-funding/examples/get-a-random-number) guide for an example where one request returns multiple random values.

## Processing simultaneous VRF requests

If you want to have multiple VRF requests processing simultaneously, create a mapping between `requestId` and the response. You might also create a mapping between the `requestId` and the address of the requester to track which address made each request.

```solidity
mapping(uint256 => uint256[]) public s_requestIdToRandomWords;
mapping(uint256 => address) public s_requestIdToAddress;
uint256 public s_requestId;

function requestRandomWords() external onlyOwner returns (uint256) {
  uint256 requestId = COORDINATOR.requestRandomWords(
    keyHash,
    s_subscriptionId,
    requestConfirmations,
    callbackGasLimit,
    numWords
  );
  s_requestIdToAddress[requestId] = msg.sender;

  // Store the latest requestId for this example.
  s_requestId = requestId;

  // Return the requestId to the requester.
  return requestId;
}

function fulfillRandomWords(
    uint256 requestId,
    uint256[] memory randomWords
  ) internal override {
  // You can return the value to the requester,
  // but this example simply stores it.
  s_requestIdToRandomWords[requestId] = randomWords;
}
```

You could also map the `requestId` to an index to keep track of the order in which a request was made.

```solidity
mapping(uint256 => uint256) s_requestIdToRequestIndex;
mapping(uint256 => uint256[]) public s_requestIndexToRandomWords;
uint256 public requestCounter;

function requestRandomWords() external onlyOwner {
  uint256 requestId = COORDINATOR.requestRandomWords(
    keyHash,
    s_subscriptionId,
    requestConfirmations,
    callbackGasLimit,
    numWords
  );
  s_requestIdToRequestIndex[requestId] = requestCounter;
  requestCounter += 1;
}

function fulfillRandomWords(
    uint256 requestId,
    uint256[] memory randomWords
  ) internal override {
  uint256 requestNumber = s_requestIdToRequestIndex[requestId];
  s_requestIndexToRandomWords[requestNumber] = randomWords;
}
```

## Processing VRF responses through different execution paths

If you want to process VRF responses depending on predetermined conditions, you can create an `enum`. When requesting for randomness, map each `requestId` to an enum. This way, you can handle different execution paths in `fulfillRandomWords`. See the following example:

```sol
// SPDX-License-Identifier: MIT
// An example of a consumer contract that relies on a subscription for funding.
// It shows how to setup multiple execution paths for handling a response.
pragma solidity ^0.8.7;

import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol";
import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol";

/**
 * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
 * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
 * DO NOT USE THIS CODE IN PRODUCTION.
 */
contract VRFv2MultiplePaths is VRFConsumerBaseV2 {
  VRFCoordinatorV2Interface COORDINATOR;

  // Your subscription ID.
  uint64 s_subscriptionId;

  // Sepolia coordinator. For other networks,
  // see https://docs.chain.link/docs/vrf/v2/supported-networks/#configurations
  address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625;

  // The gas lane to use, which specifies the maximum gas price to bump to.
  // For a list of available gas lanes on each network,
  // see https://docs.chain.link/docs/vrf/v2/supported-networks/#configurations
  bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c;

  uint32 callbackGasLimit = 100_000;

  // The default is 3, but you can set this higher.
  uint16 requestConfirmations = 3;

  // For this example, retrieve 1 random value in one request.
  // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS.
  uint32 numWords = 1;

  enum Variable {
    A,
    B,
    C
  }

  uint256 public variableA;
  uint256 public variableB;
  uint256 public variableC;

  mapping(uint256 => Variable) public requests;

  // events
  event FulfilledA(uint256 requestId, uint256 value);
  event FulfilledB(uint256 requestId, uint256 value);
  event FulfilledC(uint256 requestId, uint256 value);

  constructor(
    uint64 subscriptionId
  ) VRFConsumerBaseV2(vrfCoordinator) {
    COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
    s_subscriptionId = subscriptionId;
  }

  function updateVariable(
    uint256 input
  ) public {
    uint256 requestId =
      COORDINATOR.requestRandomWords(keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords);

    if (input % 2 == 0) {
      requests[requestId] = Variable.A;
    } else if (input % 3 == 0) {
      requests[requestId] = Variable.B;
    } else {
      requests[requestId] = Variable.C;
    }
  }

  function fulfillRandomWords(
    uint256 requestId,
    uint256[] memory randomWords
  ) internal override {
    Variable variable = requests[requestId];
    if (variable == Variable.A) {
      fulfillA(requestId, randomWords[0]);
    } else if (variable == Variable.B) {
      fulfillB(requestId, randomWords[0]);
    } else if (variable == Variable.C) {
      fulfillC(requestId, randomWords[0]);
    }
  }

  function fulfillA(
    uint256 requestId,
    uint256 randomWord
  ) private {
    // execution path A
    variableA = randomWord;
    emit FulfilledA(requestId, randomWord);
  }

  function fulfillB(
    uint256 requestId,
    uint256 randomWord
  ) private {
    // execution path B
    variableB = randomWord;
    emit FulfilledB(requestId, randomWord);
  }

  function fulfillC(
    uint256 requestId,
    uint256 randomWord
  ) private {
    // execution path C
    variableC = randomWord;
    emit FulfilledC(requestId, randomWord);
  }
}
```