Skip to main content

Command Palette

Search for a command to run...

Understanding Chainlink VRF V2 PLUS

Learn how to request, verify, and safely use cryptographically secure randomness in Solidity smart contracts

Updated
8 min read
Understanding Chainlink VRF V2 PLUS

Chainlink VRF(Varifiable Random Function) is a decentralised service that allows smart contract to access secure and probably fair randomness.

On a blockchain, every transaction and computation must be deterministic, which means true randomness cannot be generated directly on-chain. Any attempt to create randomness using values like block.timestamp, blockhash and block.prevrandao can be predicted or manipulated, making them unsafe for applications that require fairness.

This is where Chainlink comes in. Instead of generating on-chain Chainlink VRF generates random numbers off-chain using cryptographic method. Alongside this Chainlink also gives a cryptographic proof that mathametically proves that randomness was generated. This proof is then verified on-chain, ensuring unpredictability and verifiability. That means the random number cannot be known in advance, and anyone can independently verify that the number was generated fairly. In simple terms, Chainlink VRF allows smart contracts to use randomness without trusting any single party, including the oracle itself.

In this blog, you will learn**:**
• What blockchain randomness is and why it is difficult to achieve on-chain
• What is Chainlink VRF and how it works
• What VRF v2 Plus is and why it improves upon VRF v2
• The role of VRFConsumerBaseV2Plus and VRFV2PlusClient
• How to request and use secure randomness in Solidity smart contracts

What is VRF v2 Plus?

VRF v2 Plus is an upgraded version of VRF v2 that adds more flexibility and better control for developers, without changing the core security model. The original VRF v2 already provided verifiable randomness. VRF v2 Plus builds on top of the logic by improving how developers pay for randomness, manage subscriptions and configure requests.

Here’s what VRF v2 Plus brings:

  • Flexible Payments: Developers can pay for randomness using LINK tokens or native gas(like ETH).

  • Improved Subscription Control: A single subscription can fund multiple consumer contracts, that’s why scaling dApps are more efficient.

Overall, VRF v2 Plus gives developers finer control over gas limits while giving them the same trusted randomness and more control.

Understanding the Foundation

VRFConsumerBaseV2Plus:

To use VRF v2 Plus in your contract, there is one core contract you must understand correctly and that is VRFConsumerBaseV2Plus. It is an abstract base contract provided by Chainlink that your smart contract must inherit while requesting randomness using VRF v2 Plus.

As it is an abstract contract, you cannot deploy it directly; you must inherit it like this:

contract MyContract is VRFConsumerBaseV2Plus {
    // your code
}

Why do we need to inherit VRF v2 Plus?

By inheriting VRFConsumerBaseV2Plus, Chainlink ensures that:

  • Only the official VRF Coordinator contract can call fulfillRandomWords

  • Any attempt by an unauthorised address to call it will automatically revert

  • Your contract receives only verified and cryptographically proven randomness

This security guarantee is crucial for dApps where fairness matters, such as lotteries, NFT minting, gaming logic, and raffles. Without this inheritance, your contract would be vulnerable to fake randomness injection attacks, completely breaking trust in your system.

VRFConsumerBaseV2Plus acts as a security gatekeeper that ensures your smart contract accepts randomness only from Chainlink’s verified VRF Coordinator.

VRFV2PlusClient

VRFV2PlusClient is a helper library provided by Chainlink that is used to construct and format a randomness request before sending it to the VRF Coordinator. Instead of passing many parameters individually, this library allows developers to package all request settings into a single structured object. This makes the request process cleaner, safer, and easier to understand.

VRFV2PlusClient helps us define a struct(RandomWordsRequest) that contains:

  • How many random numbers you want

  • How much gas is allowed for the callback

  • How many block confirmations are required

  • Whether you want to pay in LINK or native gas

  • Any additional configuration through extraArgs

This struct is the envelope that carries our randomness request.

The RandomWordsRequest struct contains every instruction the Chainlink VRF system needs to generate and deliver secure randomness back to your smart contract.

To truly understand how Chainlink VRF v2 Plus works, it’s important to see how everything works together in a real smart contract. Below is a minimal but complete Solidity example that demonstrates how to request and receive secure randomness using Chainlink VRF v2 Plus.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { VRFConsumerBaseV2Plus } from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import { VRFV2PlusClient } from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";

contract RandomNumberGenerator is VRFConsumerBaseV2Plus {
    // VRF Coordinator address
    address private immutable vrfCoordinator;

    // VRF configuration
    bytes32 private keyHash;
    uint256 private subId;
    uint16 private requestConfirmations = 3;
    uint32 private callbackGasLimit = 200000;
    uint32 private numWords = 1;

    uint256 public randomNumber;
    uint256 public requestId;

    constructor(
        address _vrfCoordinator,
        bytes32 _keyHash,
        uint256 _subId
    ) VRFConsumerBaseV2Plus(_vrfCoordinator) {
        vrfCoordinator = _vrfCoordinator;
        keyHash = _keyHash;
        subId = _subId;
    }

    function requestRandomWords() external {
        requestId = s_vrfCoordinator.requestRandomWords(
            VRFV2PlusClient.RandomWordsRequest({
                keyHash: keyHash,
                subId: subId,
                requestConfirmations: requestConfirmations,
                callbackGasLimit: callbackGasLimit,
                numWords: numWords,
                extraArgs: VRFV2PlusClient._argsToBytes(
                    VRFV2PlusClient.ExtraArgsV1({ nativePayment: false })
                )
            })
        );
    }

    function fulfillRandomWords(uint256 /* requestId */, uint256[] calldata randomWords) internal override {
        randomNumber = randomWords[0];
    }
}

Deep Explanation of requestRandomWords function

The heart of Chainlink VRF v2 Plus lies in the requestRandomWords() call. This function sends a randomness request to the VRF Coordinator using a structured request object provided by VRFV2PlusClient.

Let’s break all its parameters.

  • keyHash: The keyHash identifies which Chainlink oracle job (or gas lane) should be used to fulfill your randomness request.

    Different key hashes mean:Different keyHashes mean:

    • Different max gas prices

    • Different request costs

    • Different response speeds

Chainlink supported networks(get your keyHashes from here)

keyHash tells Chainlink which oracle setup to use for your request.

  • subId(subscriptionId): The subId is your VRF subscription ID.

    • It holds LINK or native tokens

    • Pays for randomness requests

    • Can be shared across multiple consumer contracts

Generate your subscriptionId by clicking Create Subscription

  • requestConfirmations: This value defines how many block confirmations the Chainlink oracle should wait for before responding.

    • Lower value - faster response

    • Higher value - more security against reorgs

Example:

  • 3 confirmations is common for most applications

More confirmations mean greater security, but slightly slower fulfillment.

  • callbackGasLimit: This sets the maximum gas that can be used when calling fulfillrandomWords().

    Why this matters:

    • If it’s too low - callback fails

    • If it’s too high - unnecessary cost

You must ensure this gas limit is enough to execute all logic inside fulfillrandomWords().

  • numWords: This specifies how many random numbers you want in a single request.

    Examples:

    • one random value (lottery winner)

    • multiple random values (NFT traits)

The returned randomness will arrive as an array of size numWords.

  • extrasArgs: extraArgs allows additional configuration for your request. In VRF v2 Plus, it is primarily used to configure payment method.
VRFV2PlusClient.ExtraArgsV1({ nativePayment: false })
/* nativePayment = false → pay in LINK */
/* nativePayment = true → pay in native gas (ETH, MATIC, etc.) */
/* The arguments are encoded into bytes using _argsToBytes() before being sent to the coordinator. */

This is one of the key upgrades that makes VRF v2 Plus more flexible than VRF v2.

Explanation of fulfillRandomWords function

Once a randomness request is successfully processed by Chainlink VRF, the final step happens inside the fulfillRandomWords function. This is where your smart contract receives and uses the random values. You never call fulfillRandomWords() yourself.

  • It triggers automatically by the Chainlink VRF Coordinator

  • It executes only after the randomness proof is verified on-chain

  • This ensures the randomness is valid and untampered.

function fulfillRandomWords(
    uint256 requestId,
    uint256[] memory randomWords
) internal override {
    // Use randomness here
}
  • requestId helps track which request this response belongs to

  • randomWords contains one or more secure random values

Real-World Use Cases

NFT Minting

  • Randomly assign traits (rarity, color, attributes)

  • Ensure fair and unpredictable distribution

Lottery or Raffle

  • Select a winner from a list of participants

  • Prevent manipulation or bias

On-Chain Games

  • Random enemy behavior

  • Loot drops

  • Damage calculations

Bonus Tip: Generating Secure Randomness On-Chain

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Picking a random address from an array

contract RandomWinner {

    address[] public players;

    function addPlayer(address _player) external {
        players.push(_player);
    }

    function pickRandomWinner() public view returns (address) {
        require(players.length > 0, "No players");

        uint256 randomIndex = uint256(
            keccak256(
                abi.encodePacked(
                    block.timestamp,
                    block.prevrandao,//It is a randomness value provided by the Beacon Chain and included in each block.
                    msg.sender,
                    players.length
                )
            )
        ) % players.length;

        return players[randomIndex];
    }
}

Conclusion

Generating randomness on a blockchain is a hard problem because smart contracts are inherently deterministic. Any attempt to rely on on-chain variables like timestamps or block data can lead to predictable and manipulable outcomes, which is unacceptable for applications that depend on fairness and trust.

This is why Chainlink VRF has become the industry standard for secure randomness in Web3. By combining off-chain randomness generation with on-chain cryptographic verification, Chainlink VRF ensures that every random value used by a smart contract is provably fair, tamper-proof, and fully transparent.

With VRF v2 Plus, developers gain even more flexibility—such as native gas payments, improved subscription management, and configurable request parameters—making it easier than ever to integrate secure randomness into real-world dApps like NFT minting systems, lotteries, and blockchain games.

If you are building any application where chance, fairness, or unpredictability matters, Chainlink VRF is not just a good option—it is the correct one.

You can read more from Chainlink official documentation.

So, keep exploring, keep growing, keep building and keep levelling up your web3 skills.