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)
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.
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)
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.
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:
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.
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.
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:
Some issues we have with the API batches creation
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.
@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?).
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
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!