packages/contracts-rfq/test/MulticallTarget.t.sol
// 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;
}
}