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;
            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.


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()
        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(
            [targets, datas, values]
        return (true, execPayload);

Last updated