Chainlink VRF – Random Number from Chainlink VRF at Hardhat Test Always 0: Troubleshooting Guide

chainlinkrandomnessvrf

I tried to test chainlink vrf at hardhat test with vrfcoordinatormock. test is work fine but random words and request id are always 0.
is It correct that returning 0 from MockVRF?


    const deployContract = async(vrfCoordinatorContract : "MockVRFCoordinator" | "MockVRFCoordinatorUnfulfillable" = "MockVRFCoordinator") => {
        const Consumer = await ethers.getContractFactory("VRFv2Consumer");
        vrfCoordFactory = await ethers.getContractFactory(vrfCoordinatorContract);
        vrfCoordinatorV2Mock = await vrfCoordFactory.deploy();
        return await Consumer.deploy(MOCK_SUBSCRIPTION_ID,keyHash,vrfCoordinatorV2Mock.address);

    }

    before(async () => {
        const [owner] = await ethers.getSigners();
        owner_wallet = owner.address;
        const LotterPoly = await ethers.getContractFactory("LotterPoly");
    })
    it("Should successfully request a random number", async() => {
        vrfv2Consumer = await deployContract();

        let tx = await vrfv2Consumer.requestRandomness();
        await tx.wait();
        await new Promise(resolve => setTimeout(resolve, 30000));
        const requestId = await vrfv2Consumer.s_requestId();
        console.log(requestId);
        const randomWord = await vrfv2Consumer.s_randomWords(0);
        console.log(randomWord);


       
    })

Best Answer

Random words and request id should not be 0. If you check VRF mock contract in VRFCoordinatorV2Mock.sol, you will find that the logic to generate random words is defined in the function fulfillRandomWordsWithOverride, and the code shown below:

if (_words.length == 0) {
  _words = new uint256[](req.numWords);
  for (uint256 i = 0; i < req.numWords; i++) {
    _words[i] = uint256(keccak256(abi.encode(_requestId, i)));
  }
} else if (_words.length != req.numWords) {
  revert InvalidRandomWords();
}

The snippet of codes shows that random words are generated by encoding the _requestId and i in the for loop, so the random number should not be 0.

In your test, actually, you do not verify any result at all. If you want to verify the random words is received and greater than 0, maybe you can get the random words first and use assertion to verify it.

assert(RandomNumber.gt(ethers.constants.Zero))

Please check the unit test in the repository Chainlink hardhat starter kit.