You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

前端调用Solidity合约getEnteranceFee函数返回空数据(0x)求助

问题:调用Solidity合约view函数返回空数据(0x)

我基于Solidity和Next.js开发一款彩票DApp,将合约部署到本地Hardhat网络后,使用wagmi的useReadContract调用合约中的getEnteranceFee函数时,持续遇到错误:

ContractFunctionExecutionError: The contract function "getEnteranceFee" returned no data ("0x")

已确认合约地址正确、合约包含该函数,且仅传入了该函数的ABI,但问题仍未解决。以下是相关代码、部署输出及已执行的排查步骤:

Solidity合约代码

// 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组件代码

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部署输出

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 
------------------------------------------- 

错误信息

The contract function "getEnteranceFee" returned no data ("0x").

已执行的排查步骤

  • 将合约部署到本地Hardhat网络
  • 确认部署输出中的合约地址正确
  • 使用wagmi的useReadContract调用函数
  • 确认合约中存在getEnteranceFee函数(为view类型)

寻求可能的问题原因及解决方案。


内容的提问来源于stack exchange,提问作者ALISHA REDDY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:59:51