Autotask has incorrect ETH balance

:computer: Environment

Defender with an ethers autotask. Mainnet relayer.

:memo:Details

Our relayer is funded with ~4ETH, which is enough to execute the transactions required by our autotask. Defender seems to think that the relayer has much less ETH, so the transaction will not go through. This problem was happening intermittently, but began happening on every single run during the recent price action.

Here is the error:

2021-05-19T13:50:29.296Z	ERROR	Invoke Error 	{"errorType":"Error","errorMessage":"Error while attempting send-tx: Insufficient funds: 0.7425 ETH required but 0.1589441154 ETH are available.","stack":["Error: Error while attempting send-tx: Insufficient funds: 0.7425 ETH required but 0.1589441154 ETH are available.","    at AutotaskRelayer.execute (/opt/nodejs/node_modules/defender-relay-client/lib/autotask/index.js:72:19)","    at processTicksAndRejections (internal/process/task_queues.js:97:5)","    at async DefenderRelaySigner.sendTransaction (/opt/nodejs/node_modules/defender-relay-client/lib/ethers/signer.js:71:36)"]}
END RequestId: c99ad5cb-4d10-4edb-82ac-c3c10e9d3f20
AUTOTASK COMPLETE

Here is the code:

const { ethers } = require("ethers");

const abi = "abi is too long to paste";

const fliAdapterAddress = "0x1335D01a4B572C37f800f45D9a4b36A53a898a9b";

exports.handler = async function(credentials) {
  const provider = new DefenderRelayProvider(credentials);
  const signer = new DefenderRelaySigner(credentials, provider, { speed: 'fast' });
  return rebalance(signer, fliAdapterAddress);
}

const rebalance = async (signer, fliAdapterAddress) => {
  const fliAdapter = new ethers.Contract(fliAdapterAddress, abi, signer);

  const shouldRebalance = await fliAdapter.shouldRebalance();
  const currentLeverageRatio = await fliAdapter.getCurrentLeverageRatio();
  const maxLeverageRatio = ethers.utils.parseEther("2.35");
  
  if (shouldRebalance === 1 && currentLeverageRatio >= maxLeverageRatio) {
    return await fliAdapter.rebalance({ gasLimit: 900000});
  } else if (shouldRebalance === 2) {
    return await fliAdapter.iterateRebalance({ gasLimit: 900000});
  } else if (shouldRebalance === 3) {
    return await fliAdapter.ripcord({ gasLimit: 900000});
  }
  
  return shouldRebalance;
}

Hey @ncitron! Defender considers the relayer balance to be the current balance minus the cost of all pending transactions. The cost of a pending tx is calculated as their value plus gasLimit * gasPrice. Given you are sending txs with a gasLimit of 9M, each of these pending txs is estimated to be much more expensive than they would actually be. And the network congestion makes things worse, both by increasing gasPrice, and by causing more txs to be in a pending state until they are mined.

My suggestion would be to reduce the gasLimit to a number closer to the actual cost of the transaction. Also, if you execute this autotask in a high frequency, you may want to check whether you have a pending transaction for rebalancing before sending another: if the tx from the previous autotask run hasn’t been mined, then your code may think it still needs to rebalance and will send the same tx again.

I see. Although it seems unlikely that I would have 4 ETH worth of pending transactions. Etherscan was showing 3 pending transactions (stuck ones) at the time, with combined max fees of 0.45 ETH (gas limit is 900k, not 9M).

I definitely will look into clearing stuck transactions, but I want to make sure that there are no other issues. Maybe it could be that Etherscan was not tracking some pending transactions, which was pushing us over the 4 ETH balance?

My bad, I looked quickly through the code and must’ve added an extra zero in my head. If you send your relayer address to defender-support@openzeppelin.com, I can look into what pending txs are listed on the database to make sure everything’s running smoothly.