Solidity

在 Object.getContract 上沒有部署名稱為 VRCoordinatorV2Mock 的合約

  • July 26, 2022

收到錯誤:

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)

我的預感是 Mocks 沒有在00-deploy-mocks.ts中正確部署。當我部署 mocks 和raffle.ts文件時,它們執行得非常好,但是當我執行yarn hardhat deploy –network rinkeby時,我遇到了這個錯誤。

我的 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"]

我的 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"]

我的 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
                     )
                 })
             })
         })
     })

我在 YouTube 上關注 Patrick 的 solidity+Typescript 課程。所以,如果這對你有用,請告訴我。;)

在您的 00-deploy-mocks.ts 中,您僅在本地網路中部署 Mocks:

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

這是有道理的。

但是,您將 chainID 硬編碼為 31337,因此 01-deploy-raffle 腳本會嘗試獲取 Mock 合約。取消註釋以下行:

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

這應該可以解決您的問題:) 希望對您有所幫助!

引用自:https://ethereum.stackexchange.com/questions/132393