DelegateCall transaction to Safe sent as a call operation from Defender

I'm attempting to send a delegateCall operation to the Safe MultiSend contract via the defender admin client, however despite specifying the operation as delegateCall in the proposal metadata it seems to be transmitted as a call operation in the outgoing requests (fwiw this was working okay for me a few days ago)

:computer: Environment

Using Defender Admin Client, Defender and Safe on Goerli

:memo:Details

I am constructing the proposal according to the sample for Issuing DELEGATECALLS -- specifying delegateCall as the operation type in the proposal metadata. When reviewing via the defender UI the alert for a delegateCall operation IS displayed. Also when inspecting the network activity I can see that the delegateCall type is there as expected in the proposal metadata.

The issue comes when trying to simulate the transaction or approving it to POST to the Safe transaction service, it looks like it is transmitted as a call operation -- not sure how I can go about correcting this or if I am overlooking something.

:1234: Code to reproduce

Sample proposal configuration:

  const proposal = {
    contract: { address: '0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761', network: 'goerli' }, // Target contract
    title: 'Batch transfer test', // Title of the proposal
    description: 'Batch transfer test', // Description of the proposal
    type: 'custom', // Use 'custom' for custom admin actions
    functionInterface: { name: 'multiSend', inputs: [{ type: 'bytes', name: 'transactions' }] }, // Function ABI
    functionInputs: [transactionData], // Arguments to the function
    via: safeConfig.SAFE_ADDRESS, // Multisig address
    viaType: 'Gnosis Safe', // Must be Gnosis Safe to handle delegate calls
    metadata: { operationType: 'delegateCall' }, // Issue a delegatecall instead of a regular call
  }
  await client.createProposal(proposal)

and Defender UI messaging

Simulation result

Hi @mikemccready,

Thanks for a thorough explanation of your issue.
It could be related to our lates Defender release, I will investigate this and try to reproduce and come back to you ASAP.

1 Like

Hey @mikemccready, thanks for reporting this issue.

We've just added a fix that allows you to use delegateCall again but it'll be available until next Monday's deployment. We've identified this as a regression issue from our Batch proposals recent release, so after the next deployment, you'll be able to do it as you were doing it before.

However, let me add two things:

  1. Simulation will always fail with the setup you have, because there's is no easy way to simulate a DELEGATE_CALL. What simulation does is that it calls from the multisig address to the contract (the multisend in this case), but in reality, you call the execTransaction of the safe and then it delegates the call. This trick is done so you don't have to provide signatures in order to simulate the proposal.
  2. Since we've just released batch proposals, there's also a work in progress to create batches via API. I'm expecting it also be released the next week with its corresponding documentation, but consider that since it's a complex call with several steps, the API might have some validations/assumptions that might break the UI, but we're working hard to find a way to allow you create them without much hassle.
  3. If you simulate a batch proposal created via UI, it'll work since we simulate overriding the Safe code to DELEGATE_CALL every call, but that setup is not there for other DELEGATE_CALL type of actions.

I'll talk with the team about:

  1. Some issues we have with the API batches creation
  2. Support DELEGATE_CALL in simulation for other actions rather than batch

We'll keep you posted, but in the midtime, you can either use the UI for batching.

Best!

1 Like

Appreciate the quick response -- will keep an eye out for this!

@ernestognw is this the best way to do multiple custom calls at the moment using the API?

I followed the same thing you did @mikemccready and I see that the calls just come through with one Giant string for the multi call, but I was expected it to be decoded into each transaction as we see in the screenshots? Is there a way to decode it to a batch of transactions (that are each custom?).

For anyone following along, using steps argument is what i'm exploring at the moment.

Side note @ernestognw it appears the safe transaction service url has changed for goerli.
Noticed this in our own implementations and believe it may be effecting defender <-> safe requests for goerli as well

Hi @mikemccready

Thanks for letting us know, we've been made aware and already made the necessary changes. A fix should be in production with this week's deployment.

1 Like

Hey hey! Sorry for bumping this, but this might be relevant to my current issue.

Currently an ERC20.transfer() call reverts when I let my Defender relayer execute the transaction. This is because the balance of the relayer address is checked instead of the balance of the multsig.

Safe TX Simulation:

Reverted relayer call:

Any suggestions on how to delegate a Defender relay call are very welcome!