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,
...
connect,
disconnect,
...
}),
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) => {
setLoading(true)
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)
wallet.reload()
})
} catch (err) {
console.log('error depositEth ', err)
wallet.reload()
}
}
Can someone offer some suggestions or advice on how to solve this step?
Thanks!