Consistently seeing error msg when hit "Create admin action"

I create a new admin proposal, fill out the details, then click "Create admin action". I get the following error. I click the button again and it works fine. This has happened several times in a row.

Hi @suranap, we recently identified a bug where this happens when you try to create an admin action to be run through an EOA without being connected to your wallet at the time of clicking "Create admin action".

We'll fix it soon, but in the meantime, a workaround is to click on "Connect wallet" in the upper right corner of the app before clicking "Create admin action".

Apologies for the inconvenience!

Update: we just released a new version of Defender including the fix for this issue. Again, apologies for the inconvenience!

Thank you for the quick fix. However, Iwas always connected to my wallet when clicking the button. I’ll see if I can reproduce the bug tonight and report back.

Looks like the update fixed the previous issue but created a new one for me. I've called the same function 4 times this week without issue. Tonight I'm getting the following error. I tried to cancel this and retry. The wallet is connected properly. I can't proceed from this step.

Hi @suranap, sorry to hear that. Could you share your contract's address and network, the function you want to call and the arguments you're trying to use here? We would also need to know what execution mechanism you need to use: whether it's an EOA or a multisig and the corresponding address.

If for any reason you can't publicly disclose them please send an email to defender-support@openzeppelin.com with the information so we can further assist you.

Hey @suranap! We found an issue related to EIP1559 which we just fixed. Could you try again?

It worked, but another weird problem occurred. I issue the same transaction every day. This time the Tx failed with an "Out of gas" error when it hit the estimated gasLimit of 736,411. I ran it again and increased the gasLimit to 1M in Metamask. It worked, but only used 619,311 gas.

Why would the 1st transaction use more gas than the 2nd attempt?

Interesting! I've gone through the past harvest() calls to that contract, and all txs differ a bit in their total gas usage (by a few 1000s units). This fluctuation is expected: the costs of calls varies depending on the arguments being passed, and writing to storage yields different gas usage depending on whether the value was originally zero or if it is zeroed out during the write (check this out for a few common issues around gas estimation).

Now, the tx that failed with an oog (out of gas) used up a significantly higher amount of gas than the others (700k vs 600k). The reason for this is that all these harvest() operations get significant gas refunds when running (about 100k, as you can see on tenderly).

Now, refunds work in a funny way. You need to send enough gas to cover all the gas usage of the tx without considering refunds. And only if the tx finishes successfully (ie it doesn't revert and doesn't run oog), then the refunds are issued. So, in the failing tx, you didn't get any refunds:

My bet about what happened here: there was a minor change in the contract state between the gas estimation and the time your 0xe250 tx was mined. This caused the total gas cost of the tx to be slightly larger, which triggered the oog, which caused the refund not to be issued. So, due to a difference of just a few 1000s units of gas, it ends up looking like the failing tx consumed 100k+ more gas than the others, because it didn't get the refund.

I think that manually tweaking the gas limit is a good idea for txs where you expect fluctuation. On our end, we can add an extra 10% slack to prevent these issues.


On another topic: if you're manually running these txs once a day via Admin, have you considered using an Autotask that runs every day connected to a Relayer?

Thanks for this incredibly informative answer! I'll dive into it more to understand the issue.

As for your last question, yes I'm looking at using the Relayer feature. We need to simulate execution of a transaction to get proper values for harvest before calling. It may not fit nicely in Autotask, but I'll investigate more.

Thanks again for your help!

I'm curious: what are you using for simulation? Maybe it's something we can provide from Autotasks...

It's terrible. :frowning: I'll explain what I do now and what I'd like to do.

Now: A trusted account calls harvest with a minimum expected value to ensure we get fair pricing on all internal swaps. To determine this value, I currently have a script that uses callStatic on mainnet.

let value = contract.callStatic.harvest(0) returns the value. Then contract.harvest(value) or 1% lower to handle any weird changes in the market. However, in hardhat I have to login as the trusted account to make this work. So this is not good.

Better: The trusted account does more than call harvest. Therefore, I can use a 1/N multisig as the trusted account where the Relayer is a participant. I can simulate execution with a few steps in hardhat.

  1. Fork mainnet without a block number to use the latest blocks.
  2. Use hardhat features to impersonate the multisig and give it some ETH.
  3. Use callStatic to simulate execution as the multisig address and get the magic value.
  4. Use Relayer to execute a call via the multisig with that magic value.

If Autotask can do the simulation then this would be easy. This would generally be useful to check if a Tx could revert before submitting it.

Note: I'm using callStatic because it's easy to get the result of an external function. Otherwise, I'd have to fetch it from the event log.

Let me know if you need more details. I'd love to move all this manual work to Defender.

You don't need to do that! If you don't have a signer connected to the contract, you can override the from used for the callStatic without requiring the private key of the sender.

> c = new ethers.Contract('0xd1397aab5142a54b77b4f598f517ed421a68a325', JSON.parse(abi), ethers.provider)
> await c.callStatic.harvest(0, { from: '0x37b5b885b773d909a71443a627bcf40c66cd9644' })
BigNumber { _hex: '0x14ffd8a657ba5b36', _isBigNumber: true }

You can use that to get the value you need in an Autotask, and then issue the transaction via a Relayer.

1 Like

I did not know this! This works in the console connected to mainnet. We will try this right away in Autotask and Relayer.

Thanks. This will be much better than relying on an alarm on my phone. :slight_smile:

Awesome! Keep us posted on how it goes :slight_smile: