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

新手求助:eth.estimateGas传入合约地址作为to参数执行失败

Fixing "gas required exceeds allowance or always failing transaction" with eth.estimateGas on Contract Addresses

Hey there, let's break down why you're hitting this error and how to fix it quickly!

Why This Happens

When you call eth.estimateGas({from:'firstAccount', to:'contractAddr'}) without extra parameters, you're essentially sending an empty transaction to the contract. Most contracts either:

  • Don’t have a fallback/receive function at all, so the transaction immediately fails
  • Have a fallback function that’s not payable, but you didn’t include a value (if required)
  • Have a fallback function that intentionally reverts under certain conditions

The node recognizes this transaction as guaranteed to fail, so it throws that slightly misleading "gas required exceeds allowance" error—it really means the transaction can’t succeed no matter how much gas you allocate.

How to Fix It

You need to tell the contract which method you want to call by including the encoded data field in your estimateGas request. Here are two straightforward ways to do this with go-ethereum:

1. Use the bind Package (Recommended)

The bind package you mentioned handles ABI encoding and gas estimation automatically, so you don’t have to mess with raw data fields. Here’s a step-by-step example:

  • First, have your contract’s ABI (usually a JSON string from Solidity compilation) ready.
  • Create a bound contract instance, then use its EstimateGas method to calculate gas for specific method calls.
package main

import (
    "context"
    "log"
    "strings"
    "math/big"

    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    // Connect to your Ethereum node
    ethClient, err := ethclient.Dial("http://localhost:8545")
    if err != nil {
        log.Fatal(err)
    }

    // Replace with your contract's ABI JSON string
    contractABI := `[{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
    
    // Parse the ABI
    parsedABI, err := abi.JSON(strings.NewReader(contractABI))
    if err != nil {
        log.Fatal(err)
    }

    // Replace with your contract address and sender address
    contractAddr := common.HexToAddress("0xYourContractAddress")
    firstAccount := common.HexToAddress("0xYourFirstAccount")
    recipient := common.HexToAddress("0xRecipientAddress")

    // Create a bound contract instance
    boundContract, err := bind.NewBoundContract(contractAddr, parsedABI, ethClient, ethClient, ethClient)
    if err != nil {
        log.Fatal(err)
    }

    // Estimate gas for calling the "transfer" method with parameters
    gasLimit, err := boundContract.EstimateGas(context.Background(), "transfer", firstAccount, recipient, big.NewInt(100))
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Estimated gas: %d", gasLimit)
}

2. Manually Encode the data Field

If you want to use the raw eth.estimateGas method, you need to encode the method signature and parameters into the data field using the contract’s ABI:

package main

import (
    "context"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    ethClient, err := ethclient.Dial("http://localhost:8545")
    if err != nil {
        log.Fatal(err)
    }

    // Parse your contract's ABI
    contractABI := `[{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
    parsedABI, err := abi.JSON(strings.NewReader(contractABI))
    if err != nil {
        log.Fatal(err)
    }

    // Encode the "transfer" method call into data
    data, err := parsedABI.Pack("transfer", common.HexToAddress("0xRecipientAddress"), big.NewInt(100))
    if err != nil {
        log.Fatal(err)
    }

    // Prepare the call message with data
    callMsg := ethclient.CallMsg{
        From: common.HexToAddress("0xYourFirstAccount"),
        To:   &common.HexToAddress("0xYourContractAddress"),
        Data: data,
    }

    // Estimate gas
    gasLimit, err := ethClient.EstimateGas(context.Background(), callMsg)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Estimated gas: %d", gasLimit)
}

Edge Case: Calling the Fallback/Receive Function

If you actually want to trigger the contract’s fallback or receive function (e.g., sending ETH to the contract), make sure:

  • The fallback/receive function is marked payable
  • Include the Value field in your call message if sending ETH:
callMsg := ethclient.CallMsg{
    From:  common.HexToAddress("0xYourFirstAccount"),
    To:    &common.HexToAddress("0xYourContractAddress"),
    Value: big.NewInt(1000000000000000000), // 1 ETH
}
gasLimit, err := ethClient.EstimateGas(context.Background(), callMsg)

内容的提问来源于stack exchange,提问作者Vadim Filin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:01:57