Local testing using a mock subscription contract

This guide explains how to test Chainlink VRF v2.5 on a Remix IDE sandbox blockchain environment. Note: You can reuse the same logic on another development environment, such as Hardhat or Foundry. For example, read the Hardhat Starter Kit RandomNumberConsumer unit tests.

Benefits of local testing

Testing locally using mock contracts saves you time and resources during development. Some of the key benefits include:

  • Faster feedback loop: Immediate feedback on the functionality and correctness of your smart contracts. This helps you quickly identify and fix issues without waiting for transactions to be mined/validated on a testnet.
  • Saving your native testnet gas: Deploying and interacting with contracts requires paying gas fees. Although native testnet gas does not have any associated value, supply is limited by public faucets. Using mock contracts locally allows you to test your contracts freely without incurring any expenses.
  • Controlled environment: Local testing allows you to create a controlled environment where you can manipulate various parameters, such as block time and gas prices, to test your smart contracts' function as expected under different conditions.
  • Isolated testing: You can focus on testing individual parts of your contract, ensuring they work as intended before integrating them with other components.
  • Easier debugging: Because local tests run on your machine, you have better control over the debugging process. You can set breakpoints, inspect variables, and step through your code to identify and fix issues.
  • Comprehensive test coverage: You can create test cases to cover all possible scenarios and edge cases.

Testing logic

Complete the following tasks to test your VRF v2.5 consumer locally:

  1. Deploy the VRFCoordinatorV2_5Mock. This contract is a mock of the VRFCoordinatorV2_5 contract.
  2. Call the createSubscription function (which VRFCoordinatorV2_5Mock inherits) to create a new subscription.
  3. Call the VRFCoordinatorV2_5Mock fundSubscription function to fund your newly created subscription. Note: You can fund with an arbitrary amount.
  4. Deploy your VRF consumer contract.
  5. Call the addConsumer function (which VRFCoordinatorV2_5Mock inherits) to add your consumer contract to your subscription.
  6. Request random words from your consumer contract.
  7. Call the VRFCoordinatorV2_5Mock fulfillRandomWords function to fulfill your consumer contract request.

Testing

Open the contracts on Remix IDE

For local testing, use the default "Remix VM" environment.

Open VRFv2_5Consumer and compile in Remix:

// SPDX-License-Identifier: MIT
// An example of a consumer contract that relies on a subscription for funding.
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";

/**
 * 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.
 */

/**
 * @title The RandomNumberConsumerV2_5 contract
 * @notice A contract that gets random values from Chainlink VRF V2_5
 */
contract RandomNumberConsumerV2_5 is VRFConsumerBaseV2Plus {
    // Your subscription ID.
    uint256 immutable s_subscriptionId;

    // 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-contracts/#configurations
    bytes32 immutable s_keyHash;

    // Depends on the number of requested values that you want sent to the
    // fulfillRandomWords() function. Storing each word costs about 20,000 gas,
    // so 100,000 is a safe default for this example contract. Test and adjust
    // this limit based on the network that you select, the size of the request,
    // and the processing of the callback request in the fulfillRandomWords()
    // function.
    uint32 constant CALLBACK_GAS_LIMIT = 100000;

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

    // For this example, retrieve 2 random values in one request.
    // Cannot exceed VRFCoordinatorV2_5.MAX_NUM_WORDS.
    uint32 constant NUM_WORDS = 2;

    uint256[] public s_randomWords;
    uint256 public s_requestId;

    event ReturnedRandomness(uint256[] randomWords);

    /**
     * @notice Constructor inherits VRFConsumerBaseV2Plus
     *
     * @param subscriptionId - the subscription ID that this contract uses for funding requests
     * @param vrfCoordinator - coordinator, check https://docs.chain.link/vrf/v2-5/supported-networks
     * @param keyHash - the gas lane to use, which specifies the maximum gas price to bump to
     */
    constructor(
        uint256 subscriptionId,
        address vrfCoordinator,
        bytes32 keyHash
    ) VRFConsumerBaseV2Plus(vrfCoordinator) {
        s_keyHash = keyHash;
        s_subscriptionId = subscriptionId;
    }

    /**
     * @notice Requests randomness
     * Assumes the subscription is funded sufficiently; "Words" refers to unit of data in Computer Science
     */
    function requestRandomWords() external onlyOwner {
        // Will revert if subscription is not set and funded.
        s_requestId = s_vrfCoordinator.requestRandomWords(
            VRFV2PlusClient.RandomWordsRequest({
                keyHash: s_keyHash,
                subId: s_subscriptionId,
                requestConfirmations: REQUEST_CONFIRMATIONS,
                callbackGasLimit: CALLBACK_GAS_LIMIT,
                numWords: NUM_WORDS,
                extraArgs: VRFV2PlusClient._argsToBytes(
                    VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
                )
            })
        );
    }

    /**
     * @notice Callback function used by VRF Coordinator
     *
     * @param  - id of the request
     * @param randomWords - array of random results from VRF Coordinator
     */
    function fulfillRandomWords(
        uint256 /* requestId */,
        uint256[] calldata randomWords
    ) internal override {
        s_randomWords = randomWords;
        emit ReturnedRandomness(randomWords);
    }
}

Open VRFCoordinatorV2_5Mock in Remix:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@chainlink/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2_5Mock.sol";

On the Solidity Compiler tab, expand the Advanced Configurations section and check the Enable optimization box before you compile the VRFCoordinatorV2_5Mock contract:

Your Remix IDE file explorer should display VRFCoordinatorV2_5Mock.sol and VRFv2_5Consumer.sol:

Deploy VRFCoordinatorV2_5Mock

  1. Open VRFCoordinatorV2_5Mock.sol.

  2. Under DEPLOY & RUN TRANSACTIONS, select VRFCoordinatorV2_5Mock.

  3. Under DEPLOY, fill in the _BASEFEE, _GASPRICELINK and _WEIPERUNITLINK. These variables are used in the VRFCoordinatorV2_5Mock contract to represent the base fee, the gas price (in LINK tokens), and the current LINK/ETH price for the VRF requests.

    You can set:

    • _BASEFEE to 100000000000000000
    • _GASPRICELINK to 1000000000
    • _WEIPERUNITLINK to the current LINK/ETH price. Click the "Latest Price" button to view it:

      Latest Price

  4. Click transact to deploy the VRFCoordinatorV2_5Mock contract.

  5. Once deployed, you should see the VRFCoordinatorV2_5Mock contract under Deployed Contracts.

  6. Note the address of the deployed contract.

Create and fund a subscription

  1. Click createSubscription to create a new subscription.

  2. In the Remix IDE console, read your transaction decoded output to find the subscription ID. Note the subscription ID, which is required for multiple steps in this tutorial.

  3. Click on fundSubscription to fund your subscription. Fill in your subscription ID for _subid and set the _amount to 100000000000000000000. This mocks funding your subscription with 100 LINK.

Deploy the VRF consumer contract

  1. In the file explorer, open VRFv2_5Consumer.sol.

  2. Under DEPLOY & RUN TRANSACTIONS, select RandomNumberConsumerV2_5.

  3. Under DEPLOY, fill in the following parameters:

    • SUBSCRIPTIONID with your subscription ID
    • VRFCOORDINATOR with the deployed VRFCoordinatorV2_5Mock address
    • _KEYHASH_ with an arbitrary bytes32 (In this example, you can set the KEYHASH to 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae).
  4. Click transact to deploy the RandomNumberConsumerV2_5 contract.

  5. After the consumer contract is deployed, you should see the RandomNumberConsumerV2_5 contract under Deployed Contracts. Note the address of the deployed contract.

Add the consumer contract to your subscription

  1. Under Deployed Contracts, open the functions list of your deployed VRFCoordinatorV2_5Mock contract.

  2. Click addConsumer and fill in the _subid with your subscription ID and _consumer with your deployed consumer contract address.

  3. Click transact.

Request random words

  1. Under Deployed Contracts, open the functions list of your deployed RandomNumberConsumerV2_5 contract.

  2. Click requestRandomWords.

  3. Click s_requestId to display the last request ID. In this example, the output is 1.

  4. Note your request ID.

Fulfill the VRF request

Because you are testing on a local blockchain environment, you must fulfill the VRF request yourself.

  1. Under Deployed Contracts, open the functions list of your deployed VRFCoordinatorV2_5Mock contract.

  2. Click fulfillRandomWords and fill in _requestId with your VRF request ID and _consumer with your consumer contract address.

  3. Click transact.

Check the results

  1. Under Deployed Contracts, open the functions list of your deployed RandomNumberConsumerV2_5 contract.

  2. For each VRF request, your consumer contract requests two random words. After a request is fulfilled, the two random words are stored in the s_randomWords array. You can check the stored random words by reading the two first indexes of the s_randomWords array. To do so, click the s_randomWords function and:

    1. Fill in the index with 0 then click call to read the first random word.

    2. You can read the second random word in a similar way: fill in the index with 1 then click call to display the second random word.

Next steps

This guide demonstrated how to test a VRF v2.5 consumer contract on your local blockchain. The guide uses the Remix IDE for learning purposes, but you can reuse the same testing logic in another development environment, such as Hardhat. For example, see the Hardhat Starter Kit RandomNumberConsumer unit tests.

Get the latest Chainlink content straight to your inbox.