Multi contract execution

With dedicated msg.sender enabled, you can make use of its multi-call function batchExecuteCall to execute multiple functions on different contracts.

    function batchExecuteCall(
        address[] calldata _targets,
        bytes[] calldata _datas,
        uint256[] calldata _values
    ) external payable override onlyAuth {
        uint256 length = _targets.length;
        require(
            length == _datas.length && length == _values.length,
            "OpsProxy: Length mismatch"
        );

        for (uint256 i; i < length; i++)
            _executeCall(_targets[i], _datas[i], _values[i]);
    }

To do so, you will need to create a task with your dedicated msg.sender as the target contract address.

Get your dedicated msg.sender

Copy the address of your dedicated msg.sender which can be found in the user drop-down.

Create a task calling your dedicated msg.sender

Paste the ABI below into the ABI field and select batchExecuteCall as the function to be automated.

[{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"bytes[]","name":"_datas","type":"bytes[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"}],"name":"batchExecuteCall","outputs":[],"stateMutability":"payable","type":"function"}]

You can either predefine the arguments or have a resolver return the data.

If you are using a resolver, you must return an ABI encoded payload of the batchExecuteCall function.

Here is an example resolver that returns a payload that calls increaseCount on 2 different contracts.

interface IOpsProxy {
    function batchExecuteCall(
        address[] calldata targets,
        bytes[] calldata datas,
        uint256[] calldata values
    ) external payable;
}

interface ICounter {
    function increaseCount(uint256 _amount) external;
}

contract BatchExecCallResolver {

    address public immutable counter1;
    address public immutable counter2;
    
    constructor(address _counter1, address _counter2){
        counter1 = _counter1;
        counter2 = _counter2;
    }
    
    function checker()
        external
        view
        returns (bool canExec, bytes memory execPayload)
    {
        address[] memory targets = new address[](2);
        targets[0] = counter1;
        targets[1] = counter2;

        bytes[] memory datas = new bytes[](2);
        datas[0] = abi.encodeWithSelector(ICounter.increaseCount.selector, [1]);
        datas[1] = abi.encodeWithSelector(ICounter.increaseCount.selector, [2]);

        uint256[] memory values = new address[](2);
        values[0] = 0;
        values[1] = 0;

        execPayload = abi.encodeWithSelector(
            IOpsProxy.batchExecuteCall.selector,
            [targets, datas, values]
        );
        
        return (true, execPayload);
    }    
}

Last updated