From e2e241f8c11a3a7cc3f09fdce1c2f2a182236e7f Mon Sep 17 00:00:00 2001 From: Jack Chuma Date: Fri, 23 Jan 2026 09:12:27 -0500 Subject: [PATCH] use CBMulticall interface in multisig tooling --- script/universal/MultisigScript.sol | 67 +++++----- script/universal/MultisigScriptDeposit.sol | 16 +-- src/utils/CBMulticall.sol | 27 +--- src/utils/ICBMulticall.sol | 44 +++++++ test/universal/MultisigScriptDeposit.t.sol | 44 +++---- test/utils/CBMulticall.t.sol | 138 ++++++++------------- 6 files changed, 163 insertions(+), 173 deletions(-) create mode 100644 src/utils/ICBMulticall.sol diff --git a/script/universal/MultisigScript.sol b/script/universal/MultisigScript.sol index 519f510..4676759 100644 --- a/script/universal/MultisigScript.sol +++ b/script/universal/MultisigScript.sol @@ -7,7 +7,7 @@ import {Script} from "lib/forge-std/src/Script.sol"; import {stdJson} from "lib/forge-std/src/StdJson.sol"; import {Vm} from "lib/forge-std/src/Vm.sol"; -import {CBMulticall} from "../../src/utils/CBMulticall.sol"; +import {ICBMulticall, Call3, Call3Value} from "../../src/utils/ICBMulticall.sol"; import {IGnosisSafe, Enum} from "./IGnosisSafe.sol"; import {Signatures} from "./Signatures.sol"; @@ -406,7 +406,7 @@ abstract contract MultisigScript is Script { return scriptCalls[0]; } - CBMulticall.Call3[] memory rootCalls = new CBMulticall.Call3[](scriptCalls.length); + Call3[] memory rootCalls = new Call3[](scriptCalls.length); uint256 rootCallsIndex; Call[] memory currentGroup = new Call[](scriptCalls.length); @@ -453,7 +453,7 @@ abstract contract MultisigScript is Script { return Call({ operation: Enum.Operation.DelegateCall, target: CB_MULTICALL, - data: abi.encodeCall(CBMulticall.aggregateDelegateCalls, (rootCalls)), + data: abi.encodeCall(ICBMulticall.aggregateDelegateCalls, (rootCalls)), value: 0 }); } @@ -469,7 +469,7 @@ abstract contract MultisigScript is Script { /// @return rootCallsCount The number of root calls appended. function _aggregateCalls( Call3Type groupType, - CBMulticall.Call3[] memory rootCalls, + Call3[] memory rootCalls, uint256 rootCallsIndex, Call[] memory currentGroup, uint256 currentGroupIndex @@ -485,29 +485,29 @@ abstract contract MultisigScript is Script { } // Otherwise aggregate the calls into a single Multicall call. else { - CBMulticall.Call3 memory rootCall; + Call3 memory rootCall; if (groupType == Call3Type.CALL) { - CBMulticall.Call3[] memory call3s = new CBMulticall.Call3[](currentGroupIndex); + Call3[] memory call3s = new Call3[](currentGroupIndex); for (uint256 j; j < currentGroupIndex; j++) { call3s[j] = _toCall3(currentGroup[j]); } - rootCall = CBMulticall.Call3({ + rootCall = Call3({ target: CB_MULTICALL, allowFailure: false, - callData: abi.encodeCall(CBMulticall.aggregate3, (call3s)) + callData: abi.encodeCall(ICBMulticall.aggregate3, (call3s)) }); } else { - CBMulticall.Call3Value[] memory call3Values = new CBMulticall.Call3Value[](currentGroupIndex); + Call3Value[] memory call3Values = new Call3Value[](currentGroupIndex); for (uint256 j; j < currentGroupIndex; j++) { call3Values[j] = _toCall3Value(currentGroup[j]); } - rootCall = CBMulticall.Call3({ + rootCall = Call3({ target: CB_MULTICALL, allowFailure: false, - callData: abi.encodeCall(CBMulticall.aggregate3Value, (call3Values)) + callData: abi.encodeCall(ICBMulticall.aggregate3Value, (call3Values)) }); } @@ -620,7 +620,7 @@ abstract contract MultisigScript is Script { // Build the `execTransaction` calls chain for all the safe-to-safe approvals followed by the final script call. Call[] memory execTransactionCalls = _buildExecTransactionCalls({safes: safes, callsChain: callsChain}); - bytes memory txData = abi.encodeCall(CBMulticall.aggregate3, (_toCall3s(execTransactionCalls))); + bytes memory txData = abi.encodeCall(ICBMulticall.aggregate3, (_toCall3s(execTransactionCalls))); console.logBytes(txData); console.log("---\nSimulation link:"); @@ -895,44 +895,43 @@ abstract contract MultisigScript is Script { return Call3Type.CALL_VALUE; } - /// @notice Converts the given call to the format expected by the `CBMulticall.aggregate3` function. + /// @notice Converts the given call to the format expected by the `ICBMulticall.aggregate3` function. /// - /// @param call The call to convert to the format expected by the `CBMulticall.aggregate3` function. + /// @param call The call to convert to the format expected by the `ICBMulticall.aggregate3` function. /// - /// @return The call in the format expected by the `CBMulticall.aggregate3` function. - function _toCall3(Call memory call) internal pure returns (CBMulticall.Call3 memory) { + /// @return The call in the format expected by the `ICBMulticall.aggregate3` function. + function _toCall3(Call memory call) internal pure returns (Call3 memory) { require(call.operation == Enum.Operation.Call, "MultisigScript::_toCall3: Operation must be Call"); require(call.value == 0, "MultisigScript::_toCall3: Value must be 0"); - return CBMulticall.Call3({target: call.target, allowFailure: false, callData: call.data}); + return Call3({target: call.target, allowFailure: false, callData: call.data}); } - /// @notice Converts the given call to the format expected by the `CBMulticall.aggregate3Value` function. + /// @notice Converts the given call to the format expected by the `ICBMulticall.aggregate3Value` function. /// - /// @param call The call to convert to the format expected by the `CBMulticall.aggregate3Value` function. + /// @param call The call to convert to the format expected by the `ICBMulticall.aggregate3Value` function. /// - /// @return The call in the format expected by the `CBMulticall.aggregate3Value` function. - function _toCall3Value(Call memory call) internal pure returns (CBMulticall.Call3Value memory) { + /// @return The call in the format expected by the `ICBMulticall.aggregate3Value` function. + function _toCall3Value(Call memory call) internal pure returns (Call3Value memory) { require(call.operation == Enum.Operation.Call, "MultisigScript::_toCall3Value: Operation must be Call"); require(call.value > 0, "MultisigScript::_toCall3Value: Value must be greater than 0"); - return - CBMulticall.Call3Value({target: call.target, allowFailure: false, value: call.value, callData: call.data}); + return Call3Value({target: call.target, allowFailure: false, value: call.value, callData: call.data}); } - /// @notice Converts the given call to the format expected by the `CBMulticall.aggregateDelegateCalls` function. + /// @notice Converts the given call to the format expected by the `ICBMulticall.aggregateDelegateCalls` function. /// - /// @param call The call to convert to the format expected by the `CBMulticall.aggregateDelegateCalls` function. + /// @param call The call to convert to the format expected by the `ICBMulticall.aggregateDelegateCalls` function. /// - /// @return The call in the format expected by the `CBMulticall.aggregateDelegateCalls` function. - function _toDelegateCall3(Call memory call) internal pure returns (CBMulticall.Call3 memory) { + /// @return The call in the format expected by the `ICBMulticall.aggregateDelegateCalls` function. + function _toDelegateCall3(Call memory call) internal pure returns (Call3 memory) { require( call.operation == Enum.Operation.DelegateCall, "MultisigScript::_toDelegateCall3: Operation must be DelegateCall" ); require(call.value == 0, "MultisigScript::_toDelegateCall3: Value must be 0"); - return CBMulticall.Call3({target: call.target, allowFailure: false, callData: call.data}); + return Call3({target: call.target, allowFailure: false, callData: call.data}); } /// @notice Converts the given calls to the format expected by the `aggregate3` function. @@ -940,8 +939,8 @@ abstract contract MultisigScript is Script { /// @param calls The calls to get the call3 values for. /// /// @return The calls in the format expected by the `aggregate3` function. - function _toCall3s(Call[] memory calls) internal pure returns (CBMulticall.Call3[] memory) { - CBMulticall.Call3[] memory call3s = new CBMulticall.Call3[](calls.length); + function _toCall3s(Call[] memory calls) internal pure returns (Call3[] memory) { + Call3[] memory call3s = new Call3[](calls.length); for (uint256 i; i < calls.length; i++) { call3s[i] = _toCall3(calls[i]); } @@ -954,8 +953,8 @@ abstract contract MultisigScript is Script { /// @param calls The calls to get the call3 values for. /// /// @return The calls in the format expected by the `aggregate3` function. - function _toCall3Values(Call[] memory calls) internal pure returns (CBMulticall.Call3Value[] memory) { - CBMulticall.Call3Value[] memory call3Values = new CBMulticall.Call3Value[](calls.length); + function _toCall3Values(Call[] memory calls) internal pure returns (Call3Value[] memory) { + Call3Value[] memory call3Values = new Call3Value[](calls.length); for (uint256 i; i < calls.length; i++) { call3Values[i] = _toCall3Value(calls[i]); } @@ -968,8 +967,8 @@ abstract contract MultisigScript is Script { /// @param calls The calls to get the call3 values for. /// /// @return The calls in the format expected by the `aggregateDelegateCalls` function. - function _toDelegateCall3s(Call[] memory calls) internal pure returns (CBMulticall.Call3[] memory) { - CBMulticall.Call3[] memory delegateCall3s = new CBMulticall.Call3[](calls.length); + function _toDelegateCall3s(Call[] memory calls) internal pure returns (Call3[] memory) { + Call3[] memory delegateCall3s = new Call3[](calls.length); for (uint256 i; i < calls.length; i++) { delegateCall3s[i] = _toDelegateCall3(calls[i]); } diff --git a/script/universal/MultisigScriptDeposit.sol b/script/universal/MultisigScriptDeposit.sol index c71cf88..cae82ee 100644 --- a/script/universal/MultisigScriptDeposit.sol +++ b/script/universal/MultisigScriptDeposit.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.15; -import {CBMulticall} from "src/utils/CBMulticall.sol"; +import {ICBMulticall, Call3Value} from "src/utils/ICBMulticall.sol"; import {MultisigScript} from "./MultisigScript.sol"; import {Enum} from "./IGnosisSafe.sol"; @@ -34,9 +34,9 @@ interface IOptimismPortal2 { /// return vm.envAddress("OWNER_SAFE"); /// } /// -/// function _buildL2Calls() internal view override returns (CBMulticall.Call3Value[] memory) { -/// CBMulticall.Call3Value[] memory calls = new CBMulticall.Call3Value[](1); -/// calls[0] = CBMulticall.Call3Value({ +/// function _buildL2Calls() internal view override returns (Call3Value[] memory) { +/// Call3Value[] memory calls = new Call3Value[](1); +/// calls[0] = Call3Value({ /// target: L2_CONTRACT, /// allowFailure: false, /// callData: abi.encodeCall(IL2Contract.someFunction, (arg1, arg2)), @@ -112,7 +112,7 @@ abstract contract MultisigScriptDeposit is MultisigScript { /// The `value` field in each Call3Value struct specifies ETH to send with that /// specific L2 call. The total ETH will be bridged via the deposit transaction. /// @return calls Array of calls to execute on L2 via CBMulticall - function _buildL2Calls() internal view virtual returns (CBMulticall.Call3Value[] memory); + function _buildL2Calls() internal view virtual returns (Call3Value[] memory); ////////////////////////////////////////////////////////////////////////////////////// /// Overridden Functions /// @@ -131,13 +131,13 @@ abstract contract MultisigScriptDeposit is MultisigScript { /// function on L2 automatically distributes the ETH to each call according to its /// specified `value` field - no additional developer action is required. function _buildCalls() internal view virtual override returns (Call[] memory) { - CBMulticall.Call3Value[] memory l2Calls = _buildL2Calls(); + Call3Value[] memory l2Calls = _buildL2Calls(); require(l2Calls.length > 0, "MultisigScriptDeposit: no L2 calls"); uint256 totalValue = _sumL2CallValues(l2Calls); // Encode L2 calls as a multicall // Note: We use aggregate3Value to support per-call ETH distribution on L2 - bytes memory l2Data = abi.encodeCall(CBMulticall.aggregate3Value, (l2Calls)); + bytes memory l2Data = abi.encodeCall(ICBMulticall.aggregate3Value, (l2Calls)); // Wrap in depositTransaction call to OptimismPortal Call[] memory l1Calls = new Call[](1); @@ -167,7 +167,7 @@ abstract contract MultisigScriptDeposit is MultisigScript { /// @notice Sums the ETH values from an array of L2 calls /// @param l2Calls The array of L2 calls to sum values from /// @return total The total ETH value across all calls - function _sumL2CallValues(CBMulticall.Call3Value[] memory l2Calls) internal pure returns (uint256 total) { + function _sumL2CallValues(Call3Value[] memory l2Calls) internal pure returns (uint256 total) { for (uint256 i; i < l2Calls.length; i++) { total += l2Calls[i].value; } diff --git a/src/utils/CBMulticall.sol b/src/utils/CBMulticall.sol index 7718ad8..df18b68 100644 --- a/src/utils/CBMulticall.sol +++ b/src/utils/CBMulticall.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; +import {ICBMulticall, Call, Call3, Call3Value, Result} from "./ICBMulticall.sol"; + /// @title CBMulticall /// /// @notice Aggregate results from multiple function calls @@ -10,30 +12,7 @@ pragma solidity 0.8.15; /// permissioned calls that require a value set. When routing a call through a multisig, for example, it's /// beneficial to be able to DELEGATECALL from the multisig to this contract, thus maintaining the multisig as the /// `msg.sender` while still allowing the calls to utilize ETH already held by the multisig. -contract CBMulticall { - struct Call { - address target; - bytes callData; - } - - struct Call3 { - address target; - bool allowFailure; - bytes callData; - } - - struct Call3Value { - address target; - bool allowFailure; - uint256 value; - bytes callData; - } - - struct Result { - bool success; - bytes returnData; - } - +contract CBMulticall is ICBMulticall { address private immutable THIS_CB_MULTICALL; error MustDelegateCall(); diff --git a/src/utils/ICBMulticall.sol b/src/utils/ICBMulticall.sol new file mode 100644 index 0000000..69ee56f --- /dev/null +++ b/src/utils/ICBMulticall.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +struct Call { + address target; + bytes callData; +} + +struct Call3 { + address target; + bool allowFailure; + bytes callData; +} + +struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; +} + +struct Result { + bool success; + bytes returnData; +} + +/// @title ICBMulticall +/// @notice Interface for the CBMulticall contract used in multisig scripts. +interface ICBMulticall { + /// @notice Aggregate calls, ensuring each returns success if required + /// @param calls An array of Call3 structs + /// @return returnData An array of Result structs + function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData); + + /// @notice Aggregate calls, ensuring each returns success if required + /// @param calls An array of Call3 structs + /// @return returnData An array of Result structs + function aggregateDelegateCalls(Call3[] calldata calls) external payable returns (Result[] memory returnData); + + /// @notice Aggregate calls with a msg value + /// @param calls An array of Call3Value structs + /// @return returnData An array of Result structs + function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData); +} diff --git a/test/universal/MultisigScriptDeposit.t.sol b/test/universal/MultisigScriptDeposit.t.sol index 96c8fff..eb7c38f 100644 --- a/test/universal/MultisigScriptDeposit.t.sol +++ b/test/universal/MultisigScriptDeposit.t.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import {CBMulticall} from "src/utils/CBMulticall.sol"; +import {ICBMulticall, Call3Value} from "src/utils/ICBMulticall.sol"; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; import {Preinstalls} from "lib/optimism/packages/contracts-bedrock/src/libraries/Preinstalls.sol"; -import {MultisigScriptDeposit, IOptimismPortal2} from "script/universal/MultisigScriptDeposit.sol"; +import {MultisigScriptDeposit} from "script/universal/MultisigScriptDeposit.sol"; import {Simulation} from "script/universal/Simulation.sol"; import {IGnosisSafe} from "script/universal/IGnosisSafe.sol"; @@ -53,7 +53,7 @@ contract MultisigScriptDepositTest is Test, MultisigScriptDeposit { address internal testL2Target; uint64 internal testGasLimit = 200_000; - function() internal view returns (CBMulticall.Call3Value[] memory) buildL2CallsInternal; + function() internal view returns (Call3Value[] memory) buildL2CallsInternal; function setUp() public { // Deploy mock portal @@ -90,7 +90,7 @@ contract MultisigScriptDepositTest is Test, MultisigScriptDeposit { return safe; } - function _buildL2Calls() internal view override returns (CBMulticall.Call3Value[] memory) { + function _buildL2Calls() internal view override returns (Call3Value[] memory) { return buildL2CallsInternal(); } @@ -125,7 +125,7 @@ contract MultisigScriptDepositTest is Test, MultisigScriptDeposit { // Verify the L2 data is an aggregate3Value call bytes4 selector = bytes4(data); - assertEq(selector, CBMulticall.aggregate3Value.selector, "Should be aggregate3Value call"); + assertEq(selector, ICBMulticall.aggregate3Value.selector, "Should be aggregate3Value call"); } /// @notice Test that multiple L2 calls are batched correctly @@ -147,7 +147,7 @@ contract MultisigScriptDepositTest is Test, MultisigScriptDeposit { assertFalse(isCreation, "Should not be creation"); // Decode the aggregate3Value call to verify multiple L2 calls are included - CBMulticall.Call3Value[] memory l2Calls = abi.decode(_stripSelector(data), (CBMulticall.Call3Value[])); + Call3Value[] memory l2Calls = abi.decode(_stripSelector(data), (Call3Value[])); assertEq(l2Calls.length, 3, "Should have 3 L2 calls"); // Verify call parameters are preserved through the wrapping @@ -184,7 +184,7 @@ contract MultisigScriptDepositTest is Test, MultisigScriptDeposit { // Even single calls should be wrapped in aggregate3Value for consistency bytes4 selector = bytes4(data); - assertEq(selector, CBMulticall.aggregate3Value.selector, "Single call should still use aggregate3Value"); + assertEq(selector, ICBMulticall.aggregate3Value.selector, "Single call should still use aggregate3Value"); } /// @notice Test the full sign flow with deposit transaction @@ -251,23 +251,23 @@ contract MultisigScriptDepositTest is Test, MultisigScriptDeposit { /// Helper Functions /// ////////////////////////////////////////////////////////////////////////////////////// - function _buildSingleL2CallNoValue() internal view returns (CBMulticall.Call3Value[] memory) { - CBMulticall.Call3Value[] memory calls = new CBMulticall.Call3Value[](1); - calls[0] = CBMulticall.Call3Value({ + function _buildSingleL2CallNoValue() internal view returns (Call3Value[] memory) { + Call3Value[] memory calls = new Call3Value[](1); + calls[0] = Call3Value({ target: testL2Target, allowFailure: false, callData: abi.encodeCall(Counter.increment, ()), value: 0 }); return calls; } - function _buildMultipleL2CallsNoValue() internal view returns (CBMulticall.Call3Value[] memory) { - CBMulticall.Call3Value[] memory calls = new CBMulticall.Call3Value[](3); - calls[0] = CBMulticall.Call3Value({ + function _buildMultipleL2CallsNoValue() internal view returns (Call3Value[] memory) { + Call3Value[] memory calls = new Call3Value[](3); + calls[0] = Call3Value({ target: testL2Target, allowFailure: false, callData: abi.encodeCall(Counter.increment, ()), value: 0 }); - calls[1] = CBMulticall.Call3Value({ + calls[1] = Call3Value({ target: testL2Target, allowFailure: false, callData: abi.encodeCall(Counter.increment, ()), value: 0 }); - calls[2] = CBMulticall.Call3Value({ + calls[2] = Call3Value({ target: testL2Target, allowFailure: true, // Test allowFailure flag preservation callData: abi.encodeCall(Counter.increment, ()), @@ -276,21 +276,21 @@ contract MultisigScriptDepositTest is Test, MultisigScriptDeposit { return calls; } - function _buildL2CallsWithValue() internal view returns (CBMulticall.Call3Value[] memory) { - CBMulticall.Call3Value[] memory calls = new CBMulticall.Call3Value[](3); - calls[0] = CBMulticall.Call3Value({ + function _buildL2CallsWithValue() internal view returns (Call3Value[] memory) { + Call3Value[] memory calls = new Call3Value[](3); + calls[0] = Call3Value({ target: testL2Target, allowFailure: false, callData: abi.encodeCall(Counter.incrementPayable, ()), value: 1 ether }); - calls[1] = CBMulticall.Call3Value({ + calls[1] = Call3Value({ target: testL2Target, allowFailure: false, callData: abi.encodeCall(Counter.incrementPayable, ()), value: 2 ether }); - calls[2] = CBMulticall.Call3Value({ + calls[2] = Call3Value({ target: testL2Target, allowFailure: false, callData: abi.encodeCall(Counter.incrementPayable, ()), @@ -328,8 +328,8 @@ contract DefaultPortalTest is MultisigScriptDeposit { return address(1); } - function _buildL2Calls() internal pure override returns (CBMulticall.Call3Value[] memory) { - return new CBMulticall.Call3Value[](0); + function _buildL2Calls() internal pure override returns (Call3Value[] memory) { + return new Call3Value[](0); } function _postCheck(Vm.AccountAccess[] memory, Simulation.Payload memory) internal pure override {} diff --git a/test/utils/CBMulticall.t.sol b/test/utils/CBMulticall.t.sol index 617956f..ee2fdd7 100644 --- a/test/utils/CBMulticall.t.sol +++ b/test/utils/CBMulticall.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import {CBMulticall} from "src/utils/CBMulticall.sol"; +import {CBMulticall, Call, Call3, Call3Value, Result} from "src/utils/CBMulticall.sol"; import {CommonTest} from "test/CommonTest.t.sol"; import {MockReceiver} from "test/mocks/MockReceiver.sol"; @@ -15,10 +15,10 @@ contract CBMulticallDelegateCaller { mc = _mc; } - function aggregateDelegateCalls(CBMulticall.Call3[] calldata calls) external returns (CBMulticall.Result[] memory) { + function aggregateDelegateCalls(Call3[] calldata calls) external returns (Result[] memory) { (, bytes memory data) = address(mc).delegatecall(abi.encodeWithSelector(CBMulticall.aggregateDelegateCalls.selector, calls)); - return abi.decode(data, (CBMulticall.Result[])); + return abi.decode(data, (Result[])); } } @@ -35,13 +35,9 @@ contract CBMulticallTest is CommonTest { } function test_aggregate_returnsBlockNumberAndData() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 41) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 1) - }); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 41)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 1)}); (uint256 bn, bytes[] memory rdata) = mc.aggregate(calls); assertEq(bn, block.number); @@ -50,27 +46,19 @@ contract CBMulticallTest is CommonTest { } function test_aggregate_revertsOnFailedCall() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) - }); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector)}); vm.expectRevert(bytes("Multicall3: call failed")); mc.aggregate(calls); } function test_tryAggregate_noRequire_returnsResults() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 1) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) - }); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 1)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector)}); - CBMulticall.Result[] memory results = mc.tryAggregate(false, calls); + Result[] memory results = mc.tryAggregate(false, calls); assertEq(results.length, 2); assertTrue(results[0].success); assertEq(abi.decode(results[0].returnData, (uint256)), 2); @@ -78,27 +66,19 @@ contract CBMulticallTest is CommonTest { } function test_tryAggregate_requireSuccess_revertsOnFailure() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) - }); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector)}); vm.expectRevert(bytes("Multicall3: call failed")); mc.tryAggregate(true, calls); } function test_tryBlockAndAggregate_noRequire_returnsBlockInfoAndResults() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) - }); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector)}); - (uint256 bn, bytes32 bh, CBMulticall.Result[] memory res) = mc.tryBlockAndAggregate(false, calls); + (uint256 bn, bytes32 bh, Result[] memory res) = mc.tryBlockAndAggregate(false, calls); assertEq(bn, block.number); assertEq(bh, blockhash(block.number)); assertTrue(res[0].success); @@ -107,14 +87,10 @@ contract CBMulticallTest is CommonTest { } function test_blockAndAggregate_allSuccess_returnsResults() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 1) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 2) - }); - (uint256 bn, bytes32 bh, CBMulticall.Result[] memory res) = mc.blockAndAggregate(calls); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 1)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 2)}); + (uint256 bn, bytes32 bh, Result[] memory res) = mc.blockAndAggregate(calls); assertEq(bn, block.number); assertEq(bh, blockhash(block.number)); assertEq(res.length, 2); @@ -122,55 +98,47 @@ contract CBMulticallTest is CommonTest { } function test_blockAndAggregate_revertsOnFailure() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) - }); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector)}); vm.expectRevert(bytes("Multicall3: call failed")); mc.blockAndAggregate(calls); } function test_tryBlockAndAggregate_requireSuccess_revertsOnFailure() external { - CBMulticall.Call[] memory calls = new CBMulticall.Call[](2); - calls[0] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0) - }); - calls[1] = CBMulticall.Call({ - target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) - }); + Call[] memory calls = new Call[](2); + calls[0] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.bump.selector, 0)}); + calls[1] = Call({target: address(target), callData: abi.encodeWithSelector(MockReceiver.willRevert.selector)}); vm.expectRevert(bytes("Multicall3: call failed")); mc.tryBlockAndAggregate(true, calls); } function test_aggregate3_success() external { - CBMulticall.Call3[] memory calls3 = new CBMulticall.Call3[](1); - calls3[0] = CBMulticall.Call3({ + Call3[] memory calls3 = new Call3[](1); + calls3[0] = Call3({ target: address(target), allowFailure: false, callData: abi.encodeWithSelector(MockReceiver.bump.selector, 4) }); - CBMulticall.Result[] memory ret3 = mc.aggregate3(calls3); + Result[] memory ret3 = mc.aggregate3(calls3); assertTrue(ret3[0].success); assertEq(abi.decode(ret3[0].returnData, (uint256)), 5); } function test_aggregate3_allowedFailure_returnsFalse() external { - CBMulticall.Call3[] memory calls3 = new CBMulticall.Call3[](1); - calls3[0] = CBMulticall.Call3({ + Call3[] memory calls3 = new Call3[](1); + calls3[0] = Call3({ target: address(target), allowFailure: true, callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) }); - CBMulticall.Result[] memory ret3 = mc.aggregate3(calls3); + Result[] memory ret3 = mc.aggregate3(calls3); assertFalse(ret3[0].success); } function test_aggregate3_revertsOnNonAllowedFailure() external { - CBMulticall.Call3[] memory calls3 = new CBMulticall.Call3[](1); - calls3[0] = CBMulticall.Call3({ + Call3[] memory calls3 = new Call3[](1); + calls3[0] = Call3({ target: address(target), allowFailure: false, callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) @@ -180,31 +148,31 @@ contract CBMulticallTest is CommonTest { } function test_aggregateDelegateCalls_success() external { - CBMulticall.Call3[] memory calls3 = new CBMulticall.Call3[](1); - calls3[0] = CBMulticall.Call3({ + Call3[] memory calls3 = new Call3[](1); + calls3[0] = Call3({ target: address(target), allowFailure: false, callData: abi.encodeWithSelector(MockReceiver.bump.selector, 4) }); - CBMulticall.Result[] memory ret3 = delegateCaller.aggregateDelegateCalls(calls3); + Result[] memory ret3 = delegateCaller.aggregateDelegateCalls(calls3); assertTrue(ret3[0].success); assertEq(abi.decode(ret3[0].returnData, (uint256)), 5); } function test_aggregateDelegateCalls_allowedFailure_returnsFalse() external { - CBMulticall.Call3[] memory calls3 = new CBMulticall.Call3[](1); - calls3[0] = CBMulticall.Call3({ + Call3[] memory calls3 = new Call3[](1); + calls3[0] = Call3({ target: address(target), allowFailure: true, callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) }); - CBMulticall.Result[] memory ret3 = delegateCaller.aggregateDelegateCalls(calls3); + Result[] memory ret3 = delegateCaller.aggregateDelegateCalls(calls3); assertFalse(ret3[0].success); } function test_aggregateDelegateCalls_revertsOnNonAllowedFailure() external { - CBMulticall.Call3[] memory calls3 = new CBMulticall.Call3[](1); - calls3[0] = CBMulticall.Call3({ + Call3[] memory calls3 = new Call3[](1); + calls3[0] = Call3({ target: address(target), allowFailure: false, callData: abi.encodeWithSelector(MockReceiver.willRevert.selector) @@ -214,8 +182,8 @@ contract CBMulticallTest is CommonTest { } function test_aggregateDelegateCalls_directCall_revertsWithMustDelegateCall() external { - CBMulticall.Call3[] memory calls3 = new CBMulticall.Call3[](1); - calls3[0] = CBMulticall.Call3({ + Call3[] memory calls3 = new Call3[](1); + calls3[0] = Call3({ target: address(target), allowFailure: false, callData: abi.encodeWithSelector(MockReceiver.bump.selector, 1) @@ -227,14 +195,14 @@ contract CBMulticallTest is CommonTest { function test_aggregate3Value_success_usesContractBalance() external { vm.deal(address(mc), 1 ether); - CBMulticall.Call3Value[] memory callsV = new CBMulticall.Call3Value[](1); - callsV[0] = CBMulticall.Call3Value({ + Call3Value[] memory callsV = new Call3Value[](1); + callsV[0] = Call3Value({ target: address(target), allowFailure: false, value: 0.5 ether, callData: abi.encodeWithSelector(MockReceiver.payAndEcho.selector, 7) }); - CBMulticall.Result[] memory retV = mc.aggregate3Value(callsV); + Result[] memory retV = mc.aggregate3Value(callsV); (uint256 x, uint256 v) = abi.decode(retV[0].returnData, (uint256, uint256)); assertEq(x, 7); assertEq(v, 0.5 ether); @@ -242,8 +210,8 @@ contract CBMulticallTest is CommonTest { } function test_aggregate3Value_revertsOnNonAllowedFailure() external { - CBMulticall.Call3Value[] memory callsV = new CBMulticall.Call3Value[](1); - callsV[0] = CBMulticall.Call3Value({ + Call3Value[] memory callsV = new Call3Value[](1); + callsV[0] = Call3Value({ target: address(target), allowFailure: false, value: 0,