# Local testing using a Mock contract
Source: https://docs.chain.link/vrf/v2/direct-funding/examples/test-locally


<VrfCommon callout="directFunding" />

This guide explains how to test Chainlink VRF v2 on a [Remix IDE](https://remix-ide.readthedocs.io/en/latest/run.html#environment) sandbox blockchain environment. **Note**: You can reuse the same logic on another development environment, such as Hardhat or Truffle. For example, read the Hardhat Starter Kit [RandomNumberDirectFundingConsumer unit tests](https://github.com/smartcontractkit/hardhat-starter-kit/blob/main/test/unit/RandomNumberDirectFundingConsumer.spec.js).

> **CAUTION: Test on public testnets thoroughly**
>
> Even though local testing has several benefits, testing with a VRF mock covers the bare minimum of use cases. Make
> sure to test your consumer contract thoroughly on public testnets.

## Benefits of local testing

## Testing logic

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

1. Deploy the [VRFCoordinatorV2Mock](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol). This contract is a mock of the [VRFCoordinatorV2](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol) contract.
2. Deploy the [MockV3Aggregator](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/tests/MockV3Aggregator.sol) contract.
3. Deploy the [LinkToken](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/shared/token/ERC677/LinkToken.sol) contract.
4. Deploy the [VRFV2Wrapper](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFV2Wrapper.sol) contract.
5. Call the VRFV2Wrapper [setConfig function](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/VRFV2Wrapper.sol#L119) to set wrapper specific parameters.
6. Fund the VRFv2Wrapper subscription.
7. Call the VRFCoordinatorV2Mock [addConsumer function](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol#L230) to add the wrapper contract to your subscription.
8. Deploy your VRF consumer contract.
9. Fund your consumer contract with LINK tokens.
10. Request random words from your consumer contract.
11. Call the VRFCoordinatorV2Mock [fulfillRandomWords function](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol#L108) to fulfill your consumer contract request.

## Prerequisites

This guide will require you to finetune the gas limit when fulfilling requests. When writing, manually setting up the gas limits on RemixIDE is not supported, so you will use RemixIDE in conjunction with [Metamask](https://metamask.io/).
[Ganache](https://trufflesuite.com/ganache/) lets you quickly fire up a personal Ethereum blockchain. If you still need to install Ganache, follow the [official guide](https://trufflesuite.com/docs/ganache/quickstart/).

1. Once Ganache is installed, click the *QUICKSTART* button to start a local Ethereum node.

   (Image: Image)

   **Note**: Make sure to note the RPC server. In this example, the RPC server is *[http://127.0.0.1:7545/](http://127.0.0.1:7545/)*.

2. Follow the Metamask [official guide](https://support.metamask.io/hc/en-us/articles/360043227612-How-to-add-a-custom-network-RPC#h_01G63GGJ83DGDRCS2ZWXM37CV5) to add a custom network manually.

   (Image: Image)

3. Import a Ganache account into Metamask.
   1. On Ganache, click on the *key* symbol of the first account:

      (Image: Image)

   2. Copy the private key:

      (Image: Image)

   3. Follow the Metamask [official guide](https://support.metamask.io/hc/en-us/articles/360015489331-How-to-import-an-account) to import an account using a private key.

   4. Your Metamask is connected to *Ganache*, and you should have access to the newly imported account.

      (Image: Image)

## Testing

### Open the contracts on RemixIDE

Open *VRFCoordinatorV2Mock* and compile in Remix:

```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol";
```

Open *MockV3Aggregator* and compile in Remix:

```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/shared/mocks/MockV3Aggregator.sol";
```

Open *LinkToken* and compile in Remix:

```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@chainlink/contracts/src/v0.8/shared/token/ERC677/LinkToken.sol";
```

Open *VRFV2Wrapper* and compile in Remix:

```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

import "@chainlink/contracts/src/v0.8/vrf/VRFV2Wrapper.sol";
```

Open *RandomNumberDirectFundingConsumerV2* and compile in Remix:

```sol
// SPDX-License-Identifier: MIT
// An example of a consumer contract that directly pays for each request.
pragma solidity ^0.8.7;

import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol";
import {VRFV2WrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol";

/**
 * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
 * THIS IS AN EXAMPLE CONTRACT THAT USES UNAUDITED CODE.
 * DO NOT USE THIS CODE IN PRODUCTION.
 */
contract RandomNumberDirectFundingConsumerV2 is VRFV2WrapperConsumerBase, ConfirmedOwner {
  event RequestSent(uint256 requestId, uint32 numWords, uint256 paid);
  event RequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment);

  error InsufficientFunds(uint256 balance, uint256 paid);
  error RequestNotFound(uint256 requestId);
  error LinkTransferError(address sender, address receiver, uint256 amount);

  struct RequestStatus {
    uint256 paid; // amount paid in link
    bool fulfilled; // whether the request has been successfully fulfilled
    uint256[] randomWords;
  }

  mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */

  // past requests Id.
  uint256[] public requestIds;
  uint256 public lastRequestId;

  // configuration: https://docs.chain.link/vrf/v2/direct-funding/supported-networks#configurations
  constructor(
    address _linkAddress,
    address _wrapperAddress
  ) ConfirmedOwner(msg.sender) VRFV2WrapperConsumerBase(_linkAddress, _wrapperAddress) {}

  // Depends on the number of requested values that you want sent to the
  // fulfillRandomWords() function. 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.
  // The default is 3, but you can set this higher.
  // For this example, retrieve 2 random values in one request.
  // Cannot exceed VRFV2Wrapper.getConfig().maxNumWords.
  function requestRandomWords(
    uint32 _callbackGasLimit,
    uint16 _requestConfirmations,
    uint32 _numWords
  ) external onlyOwner returns (uint256 requestId) {
    requestId = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords);
    uint256 paid = VRF_V2_WRAPPER.calculateRequestPrice(_callbackGasLimit);
    uint256 balance = LINK.balanceOf(address(this));
    if (balance < paid) revert InsufficientFunds(balance, paid);
    s_requests[requestId] = RequestStatus({paid: paid, randomWords: new uint256[](0), fulfilled: false});
    requestIds.push(requestId);
    lastRequestId = requestId;
    emit RequestSent(requestId, _numWords, paid);
    return requestId;
  }

  function fulfillRandomWords(
    uint256 _requestId,
    uint256[] memory _randomWords
  ) internal override {
    RequestStatus storage request = s_requests[_requestId];
    if (request.paid == 0) revert RequestNotFound(_requestId);
    request.fulfilled = true;
    request.randomWords = _randomWords;
    emit RequestFulfilled(_requestId, _randomWords, request.paid);
  }

  function getNumberOfRequests() external view returns (uint256) {
    return requestIds.length;
  }

  function getRequestStatus(
    uint256 _requestId
  ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) {
    RequestStatus memory request = s_requests[_requestId];
    if (request.paid == 0) revert RequestNotFound(_requestId);
    return (request.paid, request.fulfilled, request.randomWords);
  }

  /**
   * Allow withdraw of Link tokens from the contract
   */
  function withdrawLink(
    address _receiver
  ) public onlyOwner {
    bool success = LINK.transfer(_receiver, LINK.balanceOf(address(this)));
    if (!success) {
      revert LinkTransferError(msg.sender, _receiver, LINK.balanceOf(address(this)));
    }
  }
}
```

Your RemixIDE file explorer should display the opened contracts:

(Image: Image)

### Select the correct RemixIDE environment

Under *DEPLOY & RUN TRANSACTIONS*:

1. Set the Environment to *Injected Provider - Metamask*:

   (Image: Image)

2. On Metamask, connect your Ganache account to the Remix IDE.

   (Image: Image)

3. Click on Connect. The RemixIDE environment should be set to the correct environment, and the account should be the Ganache account.

   (Image: Image)

### Deploy VRFCoordinatorV2Mock

1. Open *VRFCoordinatorV2Mock.sol*.

2. Under *DEPLOY & RUN TRANSACTIONS*, select *VRFCoordinatorV2Mock*.

   (Image: Image)

3. Under *DEPLOY*, fill in the `_BASEFEE` and `_GASPRICELINK`. These variables are used in the *VRFCoordinatorV2Mock* contract to represent the base fee and the gas price (in LINK tokens) for the VRF requests. You can set: `_BASEFEE=100000000000000000` and `_GASPRICELINK=1000000000`.

4. Click on *transact* to deploy the *VRFCoordinatorV2Mock* contract.

5. A Metamask popup will open. Click on *Confirm*.

6. Once deployed, you should see the *VRFCoordinatorV2Mock* contract under *Deployed Contracts*.

   (Image: Image)

7. Note the address of the deployed contract.

### Deploy MockV3Aggregator

The *MockV3Aggregator* contract is designed for testing purposes, allowing you to simulate an oracle price feed without interacting with the existing Chainlink network.

1. Open *MockV3Aggregator.sol*.

2. Under *DEPLOY & RUN TRANSACTIONS*, select *MockV3Aggregator*.

   (Image: Image)

3. Under *DEPLOY*, fill in `_DECIMALS` and `_INITIALANSWER`. These variables are used in the *MockV3Aggregator* contract to represent the number of decimals the aggregator's answer should have and the most recent price feed answer. You can set: `_DECIMALS=18` and `_INITIALANSWER=3000000000000000` (We are considering that `1 LINK = 0.003 native gas tokens`).

4. Click on *transact* to deploy the *MockV3Aggregator* contract.

5. A Metamask popup will open. Click on *Confirm*.

6. Once deployed, you should see the *MockV3Aggregator* contract under *Deployed Contracts*.

   (Image: Image)

7. Note the address of the deployed contract.

### Deploy LinkToken

The Chainlink VRF v2 direct funding method requires your consumer contract to pay for VRF requests in LINK. Therefore, you have to deploy the *LinkToken* contract to your local blockchain.

1. Open *LinkToken.sol*.

2. Under *DEPLOY & RUN TRANSACTIONS*, select *LinkToken*.

   (Image: Image)

3. Under *DEPLOY*, click on *transact* to deploy the *LinkToken* contract.

4. A Metamask popup will open. Click on *Confirm*.

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

   (Image: Image)

6. Note the address of the deployed contract.

### Deploy VRFV2Wrapper

As the VRF v2 direct funding [end-to-end diagram](/vrf/v2/direct-funding#request-and-receive-data) explains, the *VRFV2Wrapper* acts as a wrapper for the coordinator contract.

1. Open *VRFV2Wrapper.sol*.

2. Under *DEPLOY & RUN TRANSACTIONS*, select *VRFV2Wrapper*.

   (Image: Image)

3. Under *DEPLOY*, fill in `_LINK` with the *LinkToken* contract address, `_LINKETHFEED` with the *MockV3Aggregator* contract address, and `_COORDINATOR` with the *VRFCoordinatorV2Mock* contract address.

4. click on *transact* to deploy the *VRFV2Wrapper* contract.

5. A Metamask popup will open. Click on *Confirm*.

6. Once deployed, you should see the *VRFV2Wrapper* contract under *Deployed Contracts*.

   (Image: Image)

7. Note the address of the deployed contract.

### Configure the VRFV2Wrapper

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

2. Click on `setConfig` and fill in `_wrapperGasOverhead` with `60000`, `_coordinatorGasOverhead` with `52000`, `_wrapperPremiumPercentage` with `10`, `_keyHash` with `0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc`, and `_maxNumWords` with `10`. **Note** on these variables:

   1. `_wrapperGasOverhead`: This variable reflects the gas overhead of the wrapper's fulfillRandomWords function. The cost for this gas is passed to the user.

   2. `_coordinatorGasOverhead`: This variable reflects the gas overhead of the coordinator's `fulfillRandomWords` function. The cost for this gas is billed to the *VRFV2Wrapper* subscription and must, therefore, be included in the VRF v2 direct funding requests pricing.

   3. `_wrapperPremiumPercentage`: This variable is the premium ratio in percentage. For example, a value of 0 indicates no premium. A value of 15 indicates a 15 percent premium.

   4. `_keyHash`: The gas lane key hash value is the maximum gas price you are willing to pay for a request in wei.

   5. `_maxNumWords`: This variable is the maximum number of words requested in a VRF v2 direct funding request.

   (Image: Image)

3. click on *transact*.

4. A Metamask popup will open. Click on *Confirm*.

### Fund the VRFV2Wrapper subscription

When deployed, the *VRFV2Wrapper* contract creates a new subscription and adds itself to the newly created subscription. If you started this guide from scratch, the subscription ID should be 1.

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

2. Click `fundSubscription` to fund the *VRFV2Wrapper* subscription. In this example, you can set the `_subid` to `1` (which is your newly created subscription ID) and the `_amount` to `10000000000000000000` (10 LINK).

3. A Metamask popup will open. Click on *Confirm*.

### Deploy the VRF consumer contract

1. In the file explorer, open *RandomNumberDirectFundingConsumerV2.sol*.

2. Under *DEPLOY & RUN TRANSACTIONS*, select *RandomNumberDirectFundingConsumerV2*.

   (Image: Image)

3. Under *DEPLOY*, fill in `_LINKADDRESS_` with the *LinkToken* contract address, and `_WRAPPERADDRESS_` with the deployed *VRFV2Wrapper* address.

4. Click on *transact* to deploy the *RandomNumberDirectFundingConsumerV2* contract.

5. A Metamask popup will open. Click on *Confirm*.

6. Once deployed, you should see the *RandomNumberDirectFundingConsumerV2* contract under *Deployed Contracts*.

   (Image: Image)

7. Note the address of the deployed contract.

### Fund your VRF consumer contract

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

2. Click on *transfer* and fill in the `_to` with your consumer contract address and `_value` with LINK tokens amount. For this example, you can set the `_value` to `10000000000000000000` (10 LINK).

   (Image: Image)

3. Click on *transact*.

4. A Metamask popup will open. Click on *Confirm*.

### Request random words

Request three random words.

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

2. In `requestRandomWords`, fill in `_callbackGasLimit` with `300000`, `_requestConfirmations` with `3` and `_numWords` with `3`.

   (Image: Image)

3. Click on *transact*.

4. A Metamask popup will open.

> **NOTE: Set your gas limit in MetaMask**
>
> Remix IDE doesn't set the right gas limit, so you must [edit the
> gas limit in MetaMask](https://support.metamask.io/hc/en-us/articles/360022895972) within the **Advanced gas controls** settings.

For this example to work, set the gas limit to *400,000* in MetaMask.

First, [enable **Advanced gas controls** in your MetaMask settings](https://support.metamask.io/hc/en-us/articles/360022895972).

Before confirming your transaction in MetaMask, navigate to the screen where you can edit the gas limit: Select **Site suggested** > **Advanced** > **Advanced gas controls** and select **Edit** next to the **Gas limit** amount. Update the **Gas limit** value to *400000* and select **Save**. Finally, confirm the transaction.

1. Click on *Confirm*.

2. In the RemixIDE console, read your transaction logs to find the VRF request ID. In this example, the request ID is *1*.

   (Image: Image)

3. 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 *VRFCoordinatorV2Mock* contract.

2. Click `fulfillRandomWords` and fill in `_requestId` with your VRF request ID and `_consumer` with the *VRFV2Wrapper* contract address.

   (Image: Image)

3. Click on `transact`.

4. A Metamask popup will open.

> **NOTE: Set your gas limit in MetaMask**
>
> Remix IDE doesn't set the right gas limit, so you must [edit the
> gas limit in MetaMask](https://support.metamask.io/hc/en-us/articles/360022895972) within the **Advanced gas controls** settings.

For this example to work, set the gas limit to *1,000,000* in MetaMask.

First, [enable **Advanced gas controls** in your MetaMask settings](https://support.metamask.io/hc/en-us/articles/360022895972).

Before confirming your transaction in MetaMask, navigate to the screen where you can edit the gas limit: Select **Site suggested** > **Advanced** > **Advanced gas controls** and select **Edit** next to the **Gas limit** amount. Update the **Gas limit** value to *1000000* and select **Save**. Finally, confirm the transaction.

1. Click on *Confirm*.

2. In the RemixIDE console, read your transaction logs to find the random words.

   (Image: Image)

### Check the results

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

2. Click on `lastRequestId` to display the last request ID. In this example, the output is *1*.

   (Image: Image)

3. Click on `getRequestStatus` with `_requestId` equal to `1`:

   (Image: Image)

4. You will get the amount paid, the status, and the random words.

   (Image: Image)

   ## Next steps

This guide demonstrated how to test a VRF v2 consumer contract on your local blockchain. We made the guide on RemixIDE for learning purposes, but you can reuse the same [testing logic](#testing-logic) on another development environment, such as Truffle or Hardhat. For example, read the Hardhat Starter Kit [RandomNumberDirectFundingConsumer unit tests](https://github.com/smartcontractkit/hardhat-starter-kit/blob/main/test/unit/RandomNumberDirectFundingConsumer.spec.js).