0

I want to estimate gas cost for a smart contract function. It's a kind of deposit function which takes USDT tokens from user wallet to the pool. So I should call the approve() function first to increase allowance and then send second transaction for deposit().

This is the source code. (* It works well.)

await tokenContract.methods.approve(poolAddress, amount).send({from: account});
await poolContract.methods.deposit(amount).send({from: account});

But when I try to estimate gas cost of second transaction like this:

await tokenContract.methods.approve(poolAddress, amount).send({from: account});
await poolContract.methods.deposit(amount).estimateGas({from: account});

estimateGas() fails with this error:

Error: Error: Internal JSON-RPC error.
{
  "code": 3,
  "message": "execution reverted: ERC20: transfer amount exceeds allowance",
  "data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002845524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365000000000000000000000000000000000000000000000000"
}

What's the reason? I already called approve function before calling deposit.estimateGas(). When sending the normal transaction like first example, it works well but estimateGas() function doesn't work.

I tried one more thing. When I give 15 seconds of timeout between first function(approve) and second function(deposit.estimateGas), it works surprisingly. So in conclusion, it says that estimateGas() function doesn't work with the transactions in the same block itself.

Is it correct? If so, why?

1
  • you didn't approve , so your allowance is probably 0
    – Nulik
    Aug 7, 2021 at 1:07

1 Answer 1

3

The problem with such things is that the transaction doesn't get mined immediately. You'd need to wait for the first transaction to get mined before executing the second line.

The reason why your first version works (without estimateGas) is that it sends two transactions in succession, so the second transaction automatically "waits" for the first to complete. They are either mined in the same block or in different blocks, but regardless, the first transaction is processed first.

The reason why your second version doesn't work is that it sends one transaction and after that immediately tries to estimateGas. How estimateGas works is that it sends the same transaction, but as a local call so it will not generate a real transaction to the blockchain but only a read-only local call, which won't alter the state. Because the estimateGas is a local call, it gets executed immediately, while the first line still waits to get mined. That's why your 15 second delay also fixes the problem.

I'm not sure how to do it in web3js, but in ethers.js you could add await tx.wait() to wait for it to get mined.

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.