relevant tag icon
Multicaller
copy icon
Multicall
Utility
Deployable

Multicaller

This contract allows for efficient aggregation of multiple calls in a single transaction. It takes in an array of addresses and an array of calldata, and returns an array of the returndata from each call. (autogenerated description)

*Visit desktop site to download or deploy

Last Publish

3/4/2023
Any contract you deploy is yours.
Fully owned and controlled by your wallet.
Documentation
Source Code
Multicaller.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** * @title Multicaller * @author vectorized.eth * @notice Contract that allows for efficient aggregation * of multiple calls in a single transaction. */ contract Multicaller { // ============================================================= // ERRORS // ============================================================= /** * @dev The lengths of the input arrays are not the same. */ error ArrayLengthsMismatch(); // ============================================================= // AGGREGATION OPERATIONS // ============================================================= /** * @dev Aggregates multiple calls in a single transaction. * The `msg.value` will be forwarded to the last call. * @param targets An array of addresses to call. * @param data An array of calldata to forward to the targets. * @return An array of the returndata from each call. */ function aggregate(address[] calldata targets, bytes[] calldata data) external payable returns (bytes[] memory) { assembly { if iszero(eq(targets.length, data.length)) { // Store the function selector of `ArrayLengthsMismatch()`. mstore(returndatasize(), 0x3b800a46) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(returndatasize(), 0x20) // Store the memory offset of the `results`. mstore(0x20, data.length) // Store `data.length` into `results`. // Early return if no data. if iszero(data.length) { return(returndatasize(), 0x40) } let results := 0x40 // Left shift by 5 is equivalent to multiplying by 0x20. data.length := shl(5, data.length) // Copy the offsets from calldata into memory. calldatacopy(results, data.offset, data.length) // Offset into `results`. let resultsOffset := data.length // Pointer to the last result. let lastResults := add(0x20, data.length) // Pointer to the end of `results`. let end := add(results, data.length) for {} 1 {} { // The offset of the current bytes in the calldata. let o := add(data.offset, mload(results)) let memPtr := add(resultsOffset, 0x40) // Copy the current bytes from calldata to the memory. calldatacopy( memPtr, add(o, 0x20), // The offset of the current bytes' bytes. calldataload(o) // The length of the current bytes. ) if iszero( call( gas(), // Remaining gas. calldataload(targets.offset), // Address to call. mul(callvalue(), eq(results, lastResults)), // ETH to send. memPtr, // Start of input calldata in memory. calldataload(o), // Size of input calldata. 0x00, // We will use returndatacopy instead. 0x00 // We will use returndatacopy instead. ) ) { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } // Advance the `targets.offset`. targets.offset := add(targets.offset, 0x20) // Append the current `resultsOffset` into `results`. mstore(results, resultsOffset) results := add(results, 0x20) // Append the returndatasize, and the returndata. mstore(memPtr, returndatasize()) returndatacopy(add(memPtr, 0x20), 0x00, returndatasize()) // Advance the `resultsOffset` by `returndatasize() + 0x20`, // rounded up to the next multiple of 0x20. resultsOffset := and(add(add(resultsOffset, returndatasize()), 0x3f), not(0x1f)) if iszero(lt(results, end)) { break } } // Direct return. return(0x00, add(resultsOffset, 0x40)) } } }

Get Cookin'
share iconShare

copy iconNo-Code Deploy
copy iconDownload Source
copy iconnpx cookbookdev i Multicaller
copy icon

Bytecode

Download

Verification

Download

Last Publish

3/4/2023

Solidity Compiler

v0.8.17+commit.8df45f5f

Version

1.0.0

Cookbook is free.
Any contract you deploy is yours.
Your contract is owned and controlled by you.