I’m working on a lottery dapp using Solidity and Next.js. While trying to call the getEnteranceFeefunction
from my contract, I keep encountering the following error:
ContractFunctionExecutionError: The contract function "getEnteranceFee" returned no data ("0x").
This is happening even though my contract is successfully deployed, and the address appears correct. I even exclusively provided the abi of the function. The function doesn’t seem to return any data, and I’m not sure why.
Here’s a breakdown of the relevant code:
Solidity Contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import "@chainlink/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol";
import "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol";
import "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";
error Lottery__NotEnoughETHEntered();
error Lottery_TransferFailed();
error Lottery_NotOpen();
error Lottery_UpKeepNotNeeded(uint256 currentBalance, uint256 numPlayers, uint256 lotteryState);
contract Lottery is VRFConsumerBaseV2Plus, AutomationCompatibleInterface {
/* Type declaration*/
enum LotteryState {
OPEN,
CALCULATING
} //uint256 0=OPEN, 1=CALCULATING
/* State Variables */
uint256 private immutable i_enteranceFee;
address payable[] private s_players;
// IVRFCoordinatorV2Plus private immutable i_vrfCoordinator;
bytes32 private immutable i_gasLane;
uint256 private immutable i_subscriptionId;
uint32 private immutable i_callbackGasLimit;
uint16 private constant REQUEST_CONFIRMATIONS = 3;
uint32 private constant NUM_WORDS = 1;
//Lottery Variables
address private s_recentWinner;
LotteryState private s_lotteryState;
uint256 private s_lastTimeStamp;
uint256 private immutable i_interval;
/* Evnets*/
event LotteryEnter(address indexed player);
event RequestedLotteryWinner(uint256 indexed requestId);
event WinnerPicked(address indexed winner);
/* Functions */
constructor(
address vrfCoordinatorV2, //contract address
uint256 enteranceFee,
bytes32 gasLane,
uint256 subscriptionId,
uint32 callbackGasLimit,
uint256 interval
) VRFConsumerBaseV2Plus(vrfCoordinatorV2) {
i_enteranceFee = enteranceFee;
// i_vrfCoordinator = IVRFCoordinatorV2Plus(vrfCoordinatorV2);
i_gasLane = gasLane;
i_subscriptionId = subscriptionId;
i_callbackGasLimit = callbackGasLimit;
s_lotteryState = LotteryState.OPEN;
s_lastTimeStamp = block.timestamp; //block.timestamp is a globally known variable
i_interval = interval;
}
function enterLottery() public payable {
if (msg.value < i_enteranceFee) {
revert Lottery__NotEnoughETHEntered();
}
if (s_lotteryState != LotteryState.OPEN) {
revert Lottery_NotOpen();
}
s_players.push(payable(msg.sender));
emit LotteryEnter(msg.sender);
}
function checkUpkeep(bytes memory /*checkData*/ )
public
view
override
returns (bool upKeepNeeded, bytes memory /* performData*/ )
{
bool isOpen = (LotteryState.OPEN == s_lotteryState);
bool timePassed = (block.timestamp - s_lastTimeStamp) > i_interval;
bool hasPlayers = (s_players.length > 0);
bool hasBalance = address(this).balance > 0;
upKeepNeeded = (isOpen && timePassed && hasPlayers && hasBalance);
return (upKeepNeeded, "");
}
function performUpkeep(bytes calldata /*performData*/ ) external override {
(bool upKeepNeeded,) = checkUpkeep("");
if (!upKeepNeeded) {
revert Lottery_UpKeepNotNeeded(address(this).balance, s_players.length, uint256(s_lotteryState));
}
s_lotteryState = LotteryState.CALCULATING;
uint256 requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: i_gasLane, //gasLane
subId: i_subscriptionId, //Subscription ID that we need for funding requests (here it is to request a random number)
requestConfirmations: REQUEST_CONFIRMATIONS, //It says how many confirmations the chainlink node should wait before responding
callbackGasLimit: i_callbackGasLimit, //The limit for how much gas to use for the callback request to our contract's fulfillRandomWords() function.
numWords: NUM_WORDS, // number of random words we need
extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false}))
})
);
//THis is redudant!!
emit RequestedLotteryWinner(requestId);
}
function fulfillRandomWords(uint256, /*requestId*/ uint256[] calldata randomWords) internal override {
uint256 indexOfWinner = randomWords[0] % s_players.length;
address payable recentWinner = s_players[indexOfWinner];
s_recentWinner = recentWinner;
s_lotteryState = LotteryState.OPEN;
s_players = new address payable[](0);
s_lastTimeStamp = block.timestamp;
(bool success,) = recentWinner.call{value: address(this).balance}("");
if (!success) {
revert Lottery_TransferFailed();
}
emit WinnerPicked(recentWinner);
}
/* view / pure functions*/
function getEnteranceFee() public view returns (uint256) {
return i_enteranceFee;
}
function getPalyers(uint256 index) public view returns (address) {
return s_players[index];
}
function getRecentWinner() public view returns (address) {
return s_recentWinner;
}
function getLotteryState() public view returns (LotteryState) {
return s_lotteryState;
}
function getNumWords() public pure returns (uint256) {
return NUM_WORDS;
}
function getNumberOfPlayers() public view returns (uint256) {
return s_players.length;
}
function getLatestTimeStamp() public view returns (uint256) {
return s_lastTimeStamp;
}
function getRequestConfirmations() public pure returns (uint256) {
return REQUEST_CONFIRMATIONS;
}
function getInterval() public view returns (uint256) {
return i_interval;
}
}
React Component:
import React from "react"
import { abi, contractAddresses } from "../constants"
import { useAccount, useReadContract } from "wagmi"
import { config } from "../config"
import { useState, useEffect } from "react"
const LotteryEntrance = () => {
const [enteranceFee, setEnteranceFee] = useState(null)
const [contractAddress, setContractAddress] = useState(null)
const { isConnected, address } = useAccount()
const account = useAccount()
const chainId = account.chainId
console.log("chainId:", chainId)
// console.log(contractAddress[chainId][0])
useEffect(() => {
const fetchContractAddress = async () => {
if (chainId && contractAddresses[chainId]) {
const address = contractAddresses[chainId][0]
setContractAddress(address)
console.log("Contract Address:", address)
} else {
console.error("Invalid chain ID or contract address not found for this chain")
}
}
if (chainId) {
fetchContractAddress()
}
}, [chainId])
const {
data: fee,
isLoading,
error,
} = useReadContract({
abi: [
{
"inputs": [],
"name": "getEnteranceFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
],
address: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
functionName: "getEnteranceFee",
args: [],
enabled: !!contractAddress,
})
console.log("fee:", fee)
useEffect(() => {
async function updateUI() {
console.log("1")
if (isConnected && fee) {
console.log("2")
const enteranceFee = await fee.toString()
setEnteranceFee(enteranceFee)
console.log("enteranceFee:", enteranceFee)
}
}
updateUI()
}, [isConnected, fee])
if (isLoading) return <div>Loading entrance fee...</div>
if (error) {
console.log(error)
return <div>Error fetching entrance fee: {error.message}</div>
}
return <div>Lottery entrance fee: {enteranceFee ? `${enteranceFee}` : "N/A"}</div>
}
export default LotteryEntrance
Hardhat deployment output:
Nothing to compile Local network detected! Deploying mocks... deploying "VRFCoordinatorV2_5Mock" (tx: 0x5610f99e25943d1e61152d198e3bc82947059e723c727708f35121f44c6722f6)...: deployed at 0x5FbDB2315678afecb367f032d93F642f64180aa3 with 3057197 gas Mocks Deployed!
----------------------------------------------------
local network detected .....
subscriptionId :105366054316822285762677720084519815636149581806396942115848005774721615015833
enterance fee: BigNumber { value: "5000000000000000" } deploying "Lottery" (tx: 0x3d42183eb5cbf3c183e843614df291642e287639272f171430967a49137c1696)...: deployed at 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 with 1005908 gas Consumer is added
-------------------------------------------
Error:
The contract function "getEnteranceFee" returned no data ("0x").
I’ve verified that the contract address is correct and that the contract does contain the getRequestConfirmations function. However, the function still returns no data.
For further details, you can check out my GitHub repository: https://github.com/Alisha-Reddy/Lottery_dApp
Any suggestions on what might be causing this issue? I’d appreciate any help!
Here’s what I’ve done:
-
Deployed the contract on a local Hardhat network.
-
The contractdeployment output shows the correct contract address.
-
I’m using
useReadContract
fromwagmi
to call the function. -
The function is defined as pure in my Solidity contract.
I deployed your contract on remix and tested the function and function works:
that makes me think that your front end code is failing. i checked useReadContract
hook and you are using this address:
0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
based on docs
address Address | undefined
The contract’s address.
i checked it on etherscan, that address is an address on mainnet. you are probably using wrong address. and it is not a good approach to pass hardcoded contract address. Because if you keep redeploying the address you have to manually get the address and paste it. you should be creating a function to get the contract address.
1