Skip to content

Commit

Permalink
feat: Add Multicall3Delegatecall.so
Browse files Browse the repository at this point in the history
  • Loading branch information
maurelian committed Jan 29, 2025
1 parent ee0bf08 commit ad8ccf8
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
14 changes: 14 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export rpcUrl := env_var_or_default('ETH_RPC_URL', 'https://ethereum.publicnode.com')
export etherscanApiKey := env_var_or_default('ETHERSCAN_API_KEY', '')

install: install-contracts install-eip712sign

# install dependencies
Expand Down Expand Up @@ -34,3 +37,14 @@ add-transaction bundlePath to sig *params:
clean:
forge clean

# Deploy the Multicall3Delegatecall contract to 0x242a28aae0df515cefd09984f3057b3621646e9a
# Will fail if the contract is already deployed.
# ARGS must include --private-key or --keystore in order to deploy successfully.
deploy-multicall3-delegatecall *ARGS:
forge script DeployMulticall3Delegatecall \
--rpc-url {{rpcUrl}} \
--verify \
--verifier-api-key {{etherscanApiKey}} \
--broadcast \
{{ARGS}}
64 changes: 64 additions & 0 deletions script/Multicall3Delegatecall.sol
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();
}
}

0 comments on commit ad8ccf8

Please sign in to comment.