synapsecns/sanguine

View on GitHub
packages/contracts-rfq/test/MulticallTarget.t.sol

Summary

Maintainability
Test Coverage
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {IMulticallTarget} from "../contracts/interfaces/IMulticallTarget.sol";
import {MulticallTarget, MulticallTargetHarness} from "./harnesses/MulticallTargetHarness.sol";

import {Test} from "forge-std/Test.sol";

// solhint-disable func-name-mixedcase, ordering
contract MulticallTargetTest is Test {
    MulticallTargetHarness public harness;

    address public caller = makeAddr("Caller");

    function setUp() public {
        harness = new MulticallTargetHarness();
        harness.setAddressField(address(1));
        harness.setUintField(2);
    }

    function getEncodedStringRevertMessage() internal view returns (bytes memory) {
        return abi.encodeWithSignature("Error(string)", harness.REVERT_MESSAGE());
    }

    function getMsgSenderData() internal view returns (bytes[] memory) {
        return toArray(
            abi.encodeCall(harness.setAddressField, (address(1234))),
            abi.encodeCall(harness.addressField, ()),
            abi.encodeCall(harness.setMsgSenderAsAddressField, ()),
            abi.encodeCall(harness.addressField, ())
        );
    }

    function getMsgSenderResults() internal view returns (IMulticallTarget.Result[] memory) {
        return toArray(
            IMulticallTarget.Result(true, abi.encode(address(1234))),
            IMulticallTarget.Result(true, abi.encode(address(1234))),
            IMulticallTarget.Result(true, abi.encode(caller)),
            IMulticallTarget.Result(true, abi.encode(caller))
        );
    }

    function getNoRevertsData() internal view returns (bytes[] memory) {
        return toArray(
            abi.encodeCall(harness.addressField, ()),
            abi.encodeCall(harness.setAddressField, (address(1234))),
            abi.encodeCall(harness.setUintField, (42)),
            abi.encodeCall(harness.setAddressField, (address(0xDEADBEAF)))
        );
    }

    function getNoRevertsResults() internal pure returns (IMulticallTarget.Result[] memory) {
        return toArray(
            IMulticallTarget.Result(true, abi.encode(address(1))),
            IMulticallTarget.Result(true, abi.encode(address(1234))),
            IMulticallTarget.Result(true, abi.encode(42)),
            IMulticallTarget.Result(true, abi.encode(address(0xDEADBEAF)))
        );
    }

    function getCustomErrorRevertData() internal view returns (bytes[] memory) {
        return toArray(
            abi.encodeCall(harness.setAddressField, (address(1234))),
            abi.encodeCall(harness.setUintField, (42)),
            abi.encodeCall(harness.customErrorRevert, ()),
            abi.encodeCall(harness.setAddressField, (address(0xDEADBEAF)))
        );
    }

    function getCustomErrorRevertResults() internal pure returns (IMulticallTarget.Result[] memory) {
        return toArray(
            IMulticallTarget.Result(true, abi.encode(address(1234))),
            IMulticallTarget.Result(true, abi.encode(42)),
            IMulticallTarget.Result(false, abi.encodeWithSelector(MulticallTargetHarness.CustomError.selector)),
            IMulticallTarget.Result(true, abi.encode(address(0xDEADBEAF)))
        );
    }

    function getStringRevertData() internal view returns (bytes[] memory) {
        return toArray(
            abi.encodeCall(harness.setAddressField, (address(1234))),
            abi.encodeCall(harness.setUintField, (42)),
            abi.encodeCall(harness.revertingFunction, ()),
            abi.encodeCall(harness.setAddressField, (address(0xDEADBEAF)))
        );
    }

    function getStringRevertResults() internal view returns (IMulticallTarget.Result[] memory) {
        return toArray(
            IMulticallTarget.Result(true, abi.encode(address(1234))),
            IMulticallTarget.Result(true, abi.encode(42)),
            IMulticallTarget.Result(false, abi.encodeWithSignature("Error(string)", harness.REVERT_MESSAGE())),
            IMulticallTarget.Result(true, abi.encode(address(0xDEADBEAF)))
        );
    }

    function getUndeterminedRevertData() internal view returns (bytes[] memory) {
        return toArray(
            abi.encodeCall(harness.setAddressField, (address(1234))),
            abi.encodeCall(harness.setUintField, (42)),
            abi.encodeCall(harness.undeterminedRevert, ()),
            abi.encodeCall(harness.setAddressField, (address(0xDEADBEAF)))
        );
    }

    function getUndeterminedRevertResults() internal pure returns (IMulticallTarget.Result[] memory) {
        return toArray(
            IMulticallTarget.Result(true, abi.encode(address(1234))),
            IMulticallTarget.Result(true, abi.encode(42)),
            IMulticallTarget.Result(false, ""),
            IMulticallTarget.Result(true, abi.encode(address(0xDEADBEAF)))
        );
    }

    // ══════════════════════════════════════════ MULTICALL (NO RESULTS) ═══════════════════════════════════════════════

    function test_multicallNoResults_ignoreReverts_noReverts() public {
        bytes[] memory data = getNoRevertsData();
        harness.multicallNoResults({data: data, ignoreReverts: true});

        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallNoResults_ignoreReverts_withMsgSender() public {
        bytes[] memory data = getMsgSenderData();
        vm.prank(caller);
        harness.multicallNoResults({data: data, ignoreReverts: true});

        assertEq(harness.addressField(), caller);
        assertEq(harness.uintField(), 2);
    }

    function test_multicallNoResults_ignoreReverts_withCustomErrorRevert() public {
        bytes[] memory data = getCustomErrorRevertData();
        harness.multicallNoResults({data: data, ignoreReverts: true});

        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallNoResults_ignoreReverts_withStringRevert() public {
        bytes[] memory data = getStringRevertData();
        harness.multicallNoResults({data: data, ignoreReverts: true});

        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallNoResults_ignoreReverts_withUndeterminedRevert() public {
        bytes[] memory data = getUndeterminedRevertData();
        harness.multicallNoResults({data: data, ignoreReverts: true});

        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallNoResults_dontIgnoreReverts_noReverts() public {
        bytes[] memory data = getNoRevertsData();
        harness.multicallNoResults({data: data, ignoreReverts: false});

        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallNoResults_dontIgnoreReverts_withMsgSender() public {
        bytes[] memory data = getMsgSenderData();
        vm.prank(caller);
        harness.multicallNoResults({data: data, ignoreReverts: false});

        assertEq(harness.addressField(), caller);
        assertEq(harness.uintField(), 2);
    }

    function test_multicallNoResults_dontIgnoreReverts_withCustomErrorRevert() public {
        bytes[] memory data = getCustomErrorRevertData();
        vm.expectRevert(MulticallTargetHarness.CustomError.selector);
        harness.multicallNoResults({data: data, ignoreReverts: false});
    }

    function test_multicallNoResults_dontIgnoreReverts_withStringRevert() public {
        bytes[] memory data = getStringRevertData();
        string memory revertMessage = harness.REVERT_MESSAGE();
        vm.expectRevert(bytes(revertMessage));
        harness.multicallNoResults({data: data, ignoreReverts: false});
    }

    function test_multicallNoResults_dontIgnoreReverts_withUndeterminedRevert() public {
        bytes[] memory data = getUndeterminedRevertData();
        vm.expectRevert(MulticallTarget.MulticallTarget__UndeterminedRevert.selector);
        harness.multicallNoResults({data: data, ignoreReverts: false});
    }

    // ═════════════════════════════════════════ MULTICALL (WITH RESULTS) ══════════════════════════════════════════════

    function test_multicallWithResults_ignoreReverts_noReverts() public {
        bytes[] memory data = getNoRevertsData();
        IMulticallTarget.Result[] memory results = harness.multicallWithResults({data: data, ignoreReverts: true});

        assertEq(results, getNoRevertsResults());
        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallWithResults_ignoreReverts_withMsgSender() public {
        bytes[] memory data = getMsgSenderData();
        vm.prank(caller);
        IMulticallTarget.Result[] memory results = harness.multicallWithResults({data: data, ignoreReverts: true});

        assertEq(results, getMsgSenderResults());
        assertEq(harness.uintField(), 2);
        assertEq(harness.addressField(), caller);
    }

    function test_multicallWithResults_ignoreReverts_withCustomErrorRevert() public {
        bytes[] memory data = getCustomErrorRevertData();
        IMulticallTarget.Result[] memory results = harness.multicallWithResults({data: data, ignoreReverts: true});

        assertEq(results, getCustomErrorRevertResults());
        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallWithResults_ignoreReverts_withStringRevert() public {
        bytes[] memory data = getStringRevertData();
        IMulticallTarget.Result[] memory results = harness.multicallWithResults({data: data, ignoreReverts: true});

        assertEq(results, getStringRevertResults());
        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallWithResults_ignoreReverts_withUndeterminedRevert() public {
        bytes[] memory data = getUndeterminedRevertData();
        IMulticallTarget.Result[] memory results = harness.multicallWithResults({data: data, ignoreReverts: true});

        assertEq(results, getUndeterminedRevertResults());
        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallWithResults_dontIgnoreReverts_noReverts() public {
        bytes[] memory data = getNoRevertsData();
        IMulticallTarget.Result[] memory results = harness.multicallWithResults({data: data, ignoreReverts: false});

        assertEq(results, getNoRevertsResults());
        assertEq(harness.addressField(), address(0xDEADBEAF));
        assertEq(harness.uintField(), 42);
    }

    function test_multicallWithResults_dontIgnoreReverts_withMsgSender() public {
        bytes[] memory data = getMsgSenderData();
        vm.prank(caller);
        IMulticallTarget.Result[] memory results = harness.multicallWithResults({data: data, ignoreReverts: false});

        assertEq(results, getMsgSenderResults());
        assertEq(harness.addressField(), caller);
        assertEq(harness.uintField(), 2);
    }

    function test_multicallWithResults_dontIgnoreReverts_withCustomErrorRevert() public {
        bytes[] memory data = getCustomErrorRevertData();
        vm.expectRevert(MulticallTargetHarness.CustomError.selector);
        harness.multicallWithResults({data: data, ignoreReverts: false});
    }

    function test_multicallWithResults_dontIgnoreReverts_withStringRevert() public {
        bytes[] memory data = getStringRevertData();
        string memory revertMessage = harness.REVERT_MESSAGE();
        vm.expectRevert(bytes(revertMessage));
        harness.multicallWithResults({data: data, ignoreReverts: false});
    }

    function test_multicallWithResults_dontIgnoreReverts_withUndeterminedRevert() public {
        bytes[] memory data = getUndeterminedRevertData();
        vm.expectRevert(MulticallTarget.MulticallTarget__UndeterminedRevert.selector);
        harness.multicallWithResults({data: data, ignoreReverts: false});
    }

    // ══════════════════════════════════════════════════ VIEW ════════════════════════════════════════════════════

    function assertEq(IMulticallTarget.Result memory a, IMulticallTarget.Result memory b) internal pure {
        assertEq(a.success, b.success);
        assertEq(a.returnData, b.returnData);
    }

    function assertEq(IMulticallTarget.Result[] memory a, IMulticallTarget.Result[] memory b) internal pure {
        assertEq(a.length, b.length);
        for (uint256 i = 0; i < a.length; i++) {
            assertEq(a[i], b[i]);
        }
    }

    function toArray(
        bytes memory a,
        bytes memory b,
        bytes memory c,
        bytes memory d
    )
        internal
        pure
        returns (bytes[] memory arr)
    {
        arr = new bytes[](4);
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
        arr[3] = d;
    }

    function toArray(
        IMulticallTarget.Result memory a,
        IMulticallTarget.Result memory b,
        IMulticallTarget.Result memory c,
        IMulticallTarget.Result memory d
    )
        internal
        pure
        returns (IMulticallTarget.Result[] memory arr)
    {
        arr = new IMulticallTarget.Result[](4);
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
        arr[3] = d;
    }
}