Solidity Hardhat – No Contract Deployed with Name VRFCoordinatorV2Mock at Object.getContract Issue

hardhathardhat-deploysoliditytypescript

Error Received:

Error: ERROR processing /Users/ty/blockchainLearning/Lottery-Smart-Contract/deploy/01-deploy-raffle.ts:
Error: No Contract deployed with name VRFCoordinatorV2Mock
    at Object.getContract (/Users/ty/blockchainLearning/Lottery-Smart-Contract/node_modules/@nomiclabs/hardhat-ethers/src/internal/helpers.ts:447:11)

My hunch is that Mocks is not being deployed properly in 00-deploy-mocks.ts. When I deploy the the mocks and and raffle.ts file, they run perfectly fine however when I run yarn hardhat deploy –network rinkeby I run into this error.

My 00-deploy-mocks.ts:

import { getNamedAccounts, deployments, network, ethers } from "hardhat"
import { DeployFunction } from "hardhat-deploy/types"
import { HardhatRuntimeEnvironment } from "hardhat/types"

const BASE_FEE = "250000000000000000" // 0.25 is this the premium in LINK?
const GAS_PRICE_LINK = 1e9 // link per gas, is this the gas lane? // 0.000000001 LINK per gas

const deployMocks: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
    const { deployments, getNamedAccounts, network } = hre
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId
    // If we are on a local development network, we need to deploy mocks!
    if (chainId == 31337) {
        log("Local network detected! Deploying mocks...")
        await deploy("VRFCoordinatorV2Mock", {
            from: deployer,
            log: true,
            args: [BASE_FEE, GAS_PRICE_LINK],
        })

        log("Mocks Deployed!")
        log("----------------------------------")

        log("You are deploying to a local network, you'll need a local network running to interact")
        log(
            "Please run `yarn hardhat console --network localhost` to interact with the deployed smart contracts!"
        )
        log("----------------------------------")
    }
}
export default deployMocks
deployMocks.tags = ["all", "mocks"]

My 01-deploy-raffle.ts:

import { LogDescription } from "@ethersproject/abi"
import { ethers, network } from "hardhat"
import { DeployFunction } from "hardhat-deploy/dist/types"
import { HardhatRuntimeEnvironment } from "hardhat/types"
import {
    developmentChains,
    networkConfig,
    VERIFICATION_BLOCK_CONFIRMATIONS,
} from "../helper-hardhat-config"

import verify from "../utils/verify"

const VRF_SUB_FUND_AMOUNT = "1000000000000000000000"

const deployRaffle: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
    const { deployments, getNamedAccounts, network, ethers } = hre
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    // const chainID = network.config.chainId
    const chainID = 31337
    let vrfCoordinatorV2Address, subscriptionID

    // if on developement chain
    if (chainID == 31337) {
        const vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock")
        vrfCoordinatorV2Address = vrfCoordinatorV2Mock.address
        const txnResponse = await vrfCoordinatorV2Mock.createSubscription()
        const txnReceipt = await txnResponse.wait()
        subscriptionID = txnReceipt.events[0].args.subId

        // Fund the subscription
        await vrfCoordinatorV2Mock.fundSubscription(subscriptionID, VRF_SUB_FUND_AMOUNT)
    } else {
        // else if not on local network
        vrfCoordinatorV2Address = networkConfig[network.config.chainId!]["vrfCoordinatorV2"]
        subscriptionID = networkConfig[network.config.chainId!]["subscriptionId"]
    }

    const waitBlockConfirmations = developmentChains.includes(network.name)
        ? 1
        : VERIFICATION_BLOCK_CONFIRMATIONS
    log("----------------------------------------------------")

    const entranceFee = networkConfig[network.config.chainId!]["entranceFee"]
    const gasLane = networkConfig[network.config.chainId!]["gasLane"]
    const callbackGasLimit = networkConfig[network.config.chainId!]["callbackGasLimit"]
    const interval = networkConfig[network.config.chainId!]["interval"]

    const args = [
        vrfCoordinatorV2Address,
        entranceFee,
        gasLane,
        subscriptionID,
        callbackGasLimit,
        interval,
    ]

    const raffle = await deploy("Raffle", {
        from: deployer,
        args: args,
        log: true,
        waitConfirmations: waitBlockConfirmations,
    })

    if (!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) {
        log("Verifying...")
        await verify(raffle.address, args)
    }
    log("------------------------------------------")
}

export default deployRaffle

deployRaffle.tags = ["all", "raffle"]

My Raffle.test.ts

import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"
import { assert, expect } from "chai"
import { BigNumber, Contract } from "ethers"
import { deployments, ethers, getNamedAccounts, network } from "hardhat"
import { developmentChains, networkConfig } from "../../helper-hardhat-config"

// This runs only on a local network
!developmentChains.includes(network.name)
    ? describe.skip
    : describe("Raffle", async function () {
          let raffle: Contract
          let vrfCoordinatorV2Mock: Contract
          let entranceFee: BigNumber
          let player: SignerWithAddress
          let accounts: SignerWithAddress[]
          let raffleContract: Contract
          let interval: number

          const chainId = network.config.chainId

          beforeEach(async function () {
              accounts = await ethers.getSigners()
              player = accounts[1] // can't use accounts[0] because that is a deployer
              await deployments.fixture(["all"])
              vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock")
              raffleContract = await ethers.getContract("Raffle")
              raffle = raffleContract.connect(player)
              entranceFee = await raffle.getEntranceFee()
              interval = (await raffle.getInterval()).toNumber()
          })

          describe("constructor", function () {
              it("initalizes the raffle correctly", async () => {
                  console.log(`Network chainId: ${network.config.chainId}`)

                  const raffleState = (await raffle.getRaffleState()).toString()
                  assert.equal(raffleState, "0")
                  assert.equal(interval.toString(), networkConfig[chainId!]["interval"])
              })
          })

          describe("enterRaffle", () => {
              it("reverts when you don't pay enough", async () => {
                  await expect(raffle.enterRaffle()).to.be.revertedWith(
                      "Raffle__NotEnoughETHEntered"
                  )
              })

              it("records player when they enter", async () => {
                  await raffle.enterRaffle({ value: entranceFee })
                  const contractPlayer = await raffle.getPlayer(0)
                  assert.equal(player.address, contractPlayer)
              })

              it("emits event on enter", async () => {
                  await expect(raffle.enterRaffle({ value: entranceFee })).to.emit(
                      raffle,
                      "RaffleEnter"
                  )
              })

              it("doesn't allow entrance when raffle is calculating", async () => {
                  await raffle.enterRaffle({ value: entranceFee })

                  //   Force some time to pass
                  await network.provider.send("evm_increaseTime", [interval + 1])
                  await network.provider.request({ method: "evm_mine", params: [] })

                  // pretending to be a chainlink keeper and put raffleState in CALCULATING mode
                  await raffle.performUpkeep([])
                  await expect(raffle.enterRaffle({ value: entranceFee })).to.be.revertedWith(
                      "Raffle_NotOpen"
                  )
              })
          })

          describe("checkUpKeep", () => {
              it("returns false if people haven't sent any ETH", async () => {
                  await network.provider.send("evm_increaseTime", [interval + 1])
                  await network.provider.request({ method: "evm_mine", params: [] })

                  // Simulate calling checkUpKeep()
                  const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x")

                  // upkeepNeeded should be false because we didn't send any ETH
                  assert(!upkeepNeeded)
              })

              it("returns false if raffle isn't open", async () => {
                  await raffle.enterRaffle({ value: entranceFee })
                  await network.provider.send("evm_increaseTime", [interval + 1])
                  await network.provider.request({ method: "evm_mine", params: [] })

                  // Calling this func manke raffleState go to CALCULATING
                  await raffle.performUpkeep([])
                  const raffleState = await raffle.getRaffleState()
                  const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x")
                  assert.equal(raffleState.toString() == "1", upkeepNeeded == false)
              })

              it("returns false if enough time hasn't passed", async () => {
                  await raffle.enterRaffle({ value: entranceFee })

                  // Enough time hasn't passed - this leads to returned false
                  await network.provider.send("evm_increaseTime", [interval - 1])
                  await network.provider.request({ method: "evm_mine", params: [] })

                  const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x")
                  assert(!upkeepNeeded)
              })
              it("returns true if enough time has passed, has players, eth, and is open", async () => {
                  await raffle.enterRaffle({ value: entranceFee })
                  await network.provider.send("evm_increaseTime", [interval + 1])
                  await network.provider.request({ method: "evm_mine", params: [] })
                  const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x")

                  assert(upkeepNeeded)
              })
          })

          describe("performUpKeep", () => {
              it("can only run if checkupkeep is true", async () => {
                  await raffle.enterRaffle({ value: entranceFee })
                  await network.provider.send("evm_increaseTime", [interval + 1])
                  await network.provider.request({ method: "evm_mine", params: [] })
                  const tx = await raffle.performUpkeep("0x")
                  assert(tx)
              })

              it("reverts when checkupkeep is false", async () => {
                  await expect(raffle.performUpkeep("0x")).to.be.revertedWith(
                      "Raffle__UpkeepNotNeeded"
                  )
              })

              it("updates the raffle state and emits a requestId", async () => {
                  await raffle.enterRaffle({ value: entranceFee })
                  await network.provider.send("evm_increaseTime", [interval + 1])
                  await network.provider.request({ method: "evm_mine", params: [] })

                  // Make call to performUpKeep
                  const txnResponse = await raffle.performUpkeep("0x")
                  const txnReceipt = await txnResponse.wait(1)

                  // Get raffle state
                  const raffleState = await raffle.getRaffleState()
                  // Get requestId
                  const requestId = txnReceipt!.events![1].args!.requestId

                  // Check if reqestIf is emmited
                  assert(requestId.toNumber() > 0)
                  // Check if raffe state is updated
                  assert(raffleState == 1)
              })
          })

          describe("fulfilRandomWords", () => {
              beforeEach(async () => {
                  await raffle.enterRaffle({ value: entranceFee })
                  await network.provider.send("evm_increaseTime", [interval + 1])
                  await network.provider.request({ method: "evm_mine", params: [] })
              })

              it("picks a winner, resets, and sends money", async () => {
                  const additionalEntrances = 3
                  const startingIndex = 2

                  for (let i = startingIndex; i < startingIndex + additionalEntrances; i++) {
                      raffle = raffleContract.connect(accounts[i])
                      await raffle.enterRaffle({ value: entranceFee })
                  }

                  const startingTimeStamp = await raffle.getLastTimeStamp()

                  await new Promise<void>(async (resolve, reject) => {
                      // Subscribe once to event calling listener when the event occurs.
                      raffle.once("WinnerPicked", async () => {
                          console.log("WinnerPicked even fired!")
                          try {
                              const recentWinner = await raffle.getRecentWinner()
                              const raffleState = await raffle.getRaffleState()
                              const winnerBalance = await accounts[2].getBalance()
                              const endingTimeStamp = await raffle.getLastTimeStamp()
                              await expect(raffle.getPlayer(0)).to.be.reverted
                              assert.equal(recentWinner.toString(), accounts[2].address)
                              assert.equal(raffleState.toString(), "0")
                              assert(endingTimeStamp > startingTimeStamp)
                              assert.equal(
                                  winnerBalance.toString(),
                                  startingBalance
                                      .add(entranceFee.mul(additionalEntrances).add(entranceFee))
                                      .toString()
                              )
                              resolve()
                          } catch (e) {
                              reject(e)
                          }
                      })

                      const tx = await raffle.performUpkeep("0x")
                      const txReceipt = await tx.wait(1)
                      const startingBalance = await accounts[2].getBalance()
                      await vrfCoordinatorV2Mock.fulfillRandomWords(
                          txReceipt!.events![1].args!.requestId,
                          raffle.address
                      )
                  })
              })
          })
      })

I am following Patrick's solidity+Typescript course on YouTube. So, id this works for you let me know. 😉

Best Answer

In your 00-deploy-mocks.ts you are only deploying Mocks if it is a local network:

if (chainId == 31337) {....}

which makes sense.

You hardcoded the chainID to be 31337 however, so the 01-deploy-raffle script tries to get the Mock contract. Uncomment the following line:

// const chainID = network.config.chainId // Uncomment this
    const chainID = 31337 // Comment this

And that should fix your woes :) Hope that helps!