Solidity
在 Object.getContract 上沒有部署名稱為 VRCoordinatorV2Mock 的合約
收到錯誤:
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
這應該可以解決您的問題:) 希望對您有所幫助!