-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
78 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.15; | ||
|
||
import {Script} from "forge-std/Script.sol"; | ||
|
||
/// @title Multicall3Delegatecall | ||
/// @notice Aggregate delegate calls, ensuring each returns success if required. | ||
/// This contract is based on Multicall3 deployed on many evm chains | ||
/// at 0xcA11bde05977b3631167028862bE2a173976CA11. It has been modified to | ||
/// 1. Perform delegatecalls instead of calls. | ||
/// 2. Utility getter functions have been removed. | ||
contract Multicall3Delegatecall { | ||
struct Call3 { | ||
address target; | ||
bool allowFailure; | ||
bytes callData; | ||
} | ||
|
||
struct Result { | ||
bool success; | ||
bytes 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 aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData) { | ||
uint256 length = calls.length; | ||
returnData = new Result[](length); | ||
Call3 calldata calli; | ||
for (uint256 i = 0; i < length;) { | ||
Result memory result = returnData[i]; | ||
calli = calls[i]; | ||
(result.success, result.returnData) = calli.target.delegatecall(calli.callData); | ||
assembly { | ||
// Revert if the call fails and failure is not allowed | ||
// `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` | ||
if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { | ||
// set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) | ||
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) | ||
// set data offset | ||
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) | ||
// set length of revert string | ||
mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) | ||
// set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) | ||
mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) | ||
revert(0x00, 0x64) | ||
} | ||
} | ||
unchecked { ++i; } | ||
} | ||
} | ||
} | ||
|
||
/// @notice Deploys the Multicall3Delegatecall contract to a deterministic address. | ||
contract DeployMulticall3Delegatecall is Script { | ||
function run() public { | ||
vm.startBroadcast(); | ||
|
||
// Deploys to 0x242a28aae0df515cefd09984f3057b3621646e9a | ||
new Multicall3Delegatecall{salt: "Multicall3Delegatecall"}(); | ||
vm.stopBroadcast(); | ||
} | ||
} |