跟随Patrick C.Web3教程部署合约遇HH110错误:URL需项目ID
部署Goerli网络合约时遇到HH110错误的解决方法
执行命令 yarn hardhat deploy --network goerli 后,终端抛出错误:Error HH110: Invalid JSON-RPC response received: project id required in the url
相关代码文件
01-deploy-raffle.js
const { network, ethers } = require("hardhat") const { networkConfig, developmentChains, VERIFICATION_BLOCK_CONFIRMATIONS, } = require("../helper-hardhat-config") const { verify } = require("../utils/verify") const FUND_AMOUNT = ethers.utils.parseEther("1") // 1 Ether, or 1e18 (10^18) Wei module.exports = async ({ getNamedAccounts, deployments }) => { const { deploy, log } = deployments const { deployer } = await getNamedAccounts() const chainId = network.config.chainId let vrfCoordinatorV2Address, subscriptionId, vrfCoordinatorV2Mock if (chainId == 31337) { // create VRFV2 Subscription vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock") vrfCoordinatorV2Address = vrfCoordinatorV2Mock.address const transactionResponse = await vrfCoordinatorV2Mock.createSubscription() const transactionReceipt = await transactionResponse.wait() subscriptionId = transactionReceipt.events[0].args.subId // Fund the subscription // Our mock makes it so we don't actually have to worry about sending fund await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, FUND_AMOUNT) } else { vrfCoordinatorV2Address = networkConfig[chainId]["vrfCoordinatorV2"] subscriptionId = networkConfig[chainId]["subscriptionId"] } const waitBlockConfirmations = developmentChains.includes(network.name) ? 1 : VERIFICATION_BLOCK_CONFIRMATIONS log("----------------------------------------------------") const arguments = [ vrfCoordinatorV2Address, subscriptionId, networkConfig[chainId]["gasLane"], networkConfig[chainId]["keepersUpdateInterval"], networkConfig[chainId]["raffleEntranceFee"], networkConfig[chainId]["callbackGasLimit"], ] const raffle = await deploy("Raffle", { from: deployer, args: arguments, log: true, waitConfirmations: waitBlockConfirmations, }) // Verify the deployment if (!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) { log("Verifying...") await verify(raffle.address, arguments) } log("Enter lottery with command:") const networkName = network.name == "hardhat" ? "localhost" : network.name log(`yarn hardhat run scripts/enterRaffle.js --network ${networkName}`) log("----------------------------------------------------") } module.exports.tags = ["all", "raffle"]
helper-hardhat-config.js
const { ethers } = require("hardhat") const networkConfig = { default: { name: "hardhat", keepersUpdateInterval: "30", }, 31337: { name: "localhost", subscriptionId: "4640", gasLane: "0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc", // 30 gwei keepersUpdateInterval: "30", raffleEntranceFee: ethers.utils.parseEther("0.01"), // 0.1 ETH callbackGasLimit: "500000", // 500,000 gas }, 5: { name: "goerli", subscriptionId: "4640", gasLane: "0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15", // 30 gwei keepersUpdateInterval: "30", raffleEntranceFee: ethers.utils.parseEther("0.01"), // 0.1 ETH callbackGasLimit: "500000", // 500,000 gas vrfCoordinatorV2: "0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D", }, 1: { name: "mainnet", keepersUpdateInterval: "30", }, } const developmentChains = ["hardhat", "localhost"] const VERIFICATION_BLOCK_CONFIRMATIONS = 6 const frontEndContractsFile = "../nextjs-smartcontract-lottery-fcc/constants/contractAddresses.json" const frontEndAbiFile = "../nextjs-smartcontract-lottery-fcc/constants/abi.json" module.exports = { networkConfig, developmentChains, VERIFICATION_BLOCK_CONFIRMATIONS, frontEndContractsFile, frontEndAbiFile, }
hardhat.config.js
require("@nomiclabs/hardhat-waffle") require("@nomiclabs/hardhat-etherscan") require("hardhat-deploy") require("solidity-coverage") require("hardhat-gas-reporter") require("hardhat-contract-sizer") require("dotenv").config() /** * @type import('hardhat/config').HardhatUserConfig */ const MAINNET_RPC_URL = process.env.MAINNET_RPC_URL || process.env.ALCHEMY_MAINNET_RPC_URL || "https://eth-mainnet.alchemyapi.io/v2/your-api-key" const GOERLI_RPC_URL = process.env.GOERLI_RPC_URL || "https://eth-goerli.alchemyapi.io/v2/your-api-key" const POLYGON_MAINNET_RPC_URL = process.env.POLYGON_MAINNET_RPC_URL || "https://polygon-mainnet.alchemyapi.io/v2/your-api-key" const PRIVATE_KEY = process.env.PRIVATE_KEY || "0x" // optional const MNEMONIC = process.env.MNEMONIC || "your mnemonic" // Your API key for Etherscan, obtain one at https://etherscan.io/ const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY || "Your etherscan API key" const POLYGONSCAN_API_KEY = process.env.POLYGONSCAN_API_KEY || "Your polygonscan API key" const REPORT_GAS = process.env.REPORT_GAS || false module.exports = { defaultNetwork: "hardhat", networks: { hardhat: { // // If you want to do some forking, uncomment this // forking: { // url: MAINNET_RPC_URL // } chainId: 31337, }, localhost: { chainId: 31337, }, goerli: { url: GOERLI_RPC_URL, accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [], // accounts: { // mnemonic: MNEMONIC, // }, saveDeployments: true, chainId: 5, }, mainnet: { url: MAINNET_RPC_URL, accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [], // accounts: { // mnemonic: MNEMONIC, // }, saveDeployments: true, chainId: 1, }, polygon: { url: POLYGON_MAINNET_RPC_URL, accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [], saveDeployments: true, chainId: 137, }, }, etherscan: { // yarn hardhat verify --network <NETWORK> <CONTRACT_ADDRESS> <CONSTRUCTOR_PARAMETERS> apiKey: { goerli: ETHERSCAN_API_KEY, polygon: POLYGONSCAN_API_KEY, }, }, gasReporter: { enabled: REPORT_GAS, currency: "USD", outputFile: "gas-report.txt", noColors: true, // coinmarketcap: process.env.COINMARKETCAP_API_KEY, }, contractSizer: { runOnCompile: false, only: ["Raffle"], }, namedAccounts: { deployer: { default: 0, // here this will by default take the first account as deployer 1: 0, // similarly on mainnet it will take the first account as deployer. Note though that depending on how hardhat network are configured, the account 0 on one network can be different than on another }, player: { default: 1, }, }, solidity: { compilers: [ { version: "0.8.7", }, { version: "0.4.24", }, ], }, mocha: { timeout: 500000, // 500 seconds max for running tests }, }
错误原因及解决方案
错误原因
该错误是因为Goerli RPC URL未配置有效项目ID,导致Hardhat无法建立与Goerli测试网的连接。当前代码中使用了占位符URL,没有替换为实际可用的RPC地址。
解决步骤
创建/配置.env文件:在项目根目录下创建
.env文件(如果不存在),添加以下内容:GOERLI_RPC_URL=https://eth-goerli.alchemyapi.io/v2/你的项目ID PRIVATE_KEY=你的钱包私钥 ETHERSCAN_API_KEY=你的Etherscan API密钥(可选,用于合约验证)其中
你的项目ID需要替换为你从Alchemy或其他RPC服务商获取的有效项目ID。确认配置加载:当前
hardhat.config.js已通过dotenv加载环境变量,无需额外修改代码。替换默认订阅ID:
helper-hardhat-config.js中Goerli网络的subscriptionId是默认值,需要替换为你在Chainlink VRF平台创建的专属订阅ID,避免后续出现订阅权限问题。重新执行部署命令:
yarn hardhat deploy --network goerli
内容的提问来源于stack exchange,提问作者Aditya Prasad
相关产品推荐
相关产品推荐

