I'm trying to connect with contracts deployed on the Rinkeby testnet using a node provider. When I was testing using hardhat as a local node, the contracts are called with no problem, but when I change to Rinkeby, I get an error cannot estimate gas; transaction may fail or may require manual gas limit (error={"code":-32000,"message":"execution reverted"}, method="call" for all the contract functions I'm trying to call. I've seen forums saying that it's usually due to the node being unable to estimate the gas limit and that I should manually set it.

By the way, Web3-React and Ethers.js don't contradict each other despite the naming. Web3-React is simply a React state machine that dynamically keeps track of my current wallet address, chain id, and browser provider Web3Provider, which I also use to create Contract instances using its signer. I use Ethers to create the Contract instances, format and parse data, and use its getDefaultProvider method to connect me to Alchemy. I made sure my rinkeby account had ether, and to change my local contract address variables to those of the ones deployed.

I'm also honestly a bit confused on what to do next, shouldn't the app suffice with just the Web3Provider instance from Web3-React? I've read on a lot of tutorials but nothing that explains something like this specifically.

Some example code below to show how the project is structured:

I've been keeping track of variables from Web3-React globally via React Context like this:

const value = useMemo<ContextWallet>(
    () => ({
      isActive: web3React.active,
      account: web3React.account ?? undefined,
      chainId: web3React.chainId,
      library: web3React.library,

For clarification, web3React.library essentially returns new Web3Provider(window.ethereum) where Web3Provider is imported from @ethersproject/providers. web3React.account returns from the ethereum request eth_accounts, web3React.chainId is from the request eth_chainId or net_version, and web3React.isActive lets us know whether the connection is working or not.

To create a contract instance via a signer I use the following functions:

export function getContract(address: string, ABI: any, library: Web3Provider, account?: string): Contract {
  if (!isAddress(address) || address === AddressZero) {
    throw Error(`Invalid 'address' parameter '${address}'.`)

  const contract = new Contract(address, ABI, getProviderOrSigner(library, account) as any)
  return contract

export function getProviderOrSigner(library: Web3Provider, account?: string): Web3Provider | JsonRpcSigner {
  return account ? getSigner(library, account) : library

function getSigner(library: Web3Provider, account: string): JsonRpcSigner {
  return library.getSigner(account).connectUnchecked()

As for the provider to Alchemy, I did it like this but I don't really know what to do next:

getDefaultProvider(getNetworkName(Number(CHAIN_ID)), { alchemy: ALCHEMY_API_KEY })

The next snippet is an example of how I call a contract function:

const depositEth = async (amount: number, gas: any) => {
    if (!farmContract || !vaultContract) return
    try {
      const tx = await farmContract.depositEth({
        value: parseEther(amount),
        gasPrice: gas,
      await tx.wait()
      await farmContract.once('EthDeposited', (sender, amount, tx) => {

        // At this point, the transaction should have been mined already
        console.log('EthDeposited event detected: ', tx)
    } catch (err) {
      console.log('error depositEth ', err)

Can someone offer some suggestions or advice on how to solve this step?


1 Answer 1


you should put gasLimit either manually or dynamically in last argument of SC method call.

 const tx = await farmContract.depositEth({
    gasLimit: <estimate number>,

for getting the gas limit dynamically, use this before calling the actual method:

const estimateGas = await farmContract.estimateGas['depositEth']()
const tx = await farmContract.depositEth({
    gasLimit: estimateGas,

Also, you can add new a bit margin to gasLimit using this:

export function calculateGasMargin(value: BigNumber, margin = 1000):BigNumber {
  return value.mul(BigNumber.from(10000).add(BigNumber.from(margin))).div(BigNumber.from(10000)) 

wrap gasLimit with calculateGasMargin:

    gasLimit: calculateGasMargin(estimateGas),

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.