diff --git a/contracts/interfaces/IMulticall.sol b/contracts/interfaces/IMulticall.sol new file mode 100644 index 00000000..e13381b8 --- /dev/null +++ b/contracts/interfaces/IMulticall.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title IMulticall + * @notice This contract is a multi-functional smart contract which allows for multiple + * contract calls in a single transaction. + */ +interface IMulticall { + error MulticallFailed(bytes err); + + /** + * @notice Performs multiple delegate calls and returns the results of all calls as an array + * @dev This function requires that the contract has sufficient balance for the delegate calls. + * If any of the calls fail, the function will revert with the failure message. + * @param data An array of encoded function calls + * @return results An bytes array with the return data of each function call + */ + function multicall(bytes[] calldata data) external payable returns (bytes[] memory results); +} diff --git a/contracts/utils/Multicall.sol b/contracts/utils/Multicall.sol new file mode 100644 index 00000000..312396b5 --- /dev/null +++ b/contracts/utils/Multicall.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import { IMulticall } from '../interfaces/IMulticall.sol'; + +/** + * @title Multicall + * @notice This contract is a multi-functional smart contract which allows for multiple + * contract calls in a single transaction. + */ +contract Multicall is IMulticall { + + /** + * @notice Performs multiple delegate calls and returns the results of all calls as an array + * @dev This function requires that the contract has sufficient balance for the delegate calls. + * If any of the calls fail, the function will revert with the failure message. + * @param data An array of encoded function calls + * @return results An bytes array with the return data of each function call + */ + function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) { + results = new bytes[](data.length); + bool success; + bytes memory result; + for (uint256 i = 0; i < data.length; ++i) { + (success, result) = address(this).delegatecall(data[i]); + + if (!success) { + revert(string(result)); + } + + results[i] = result; + } + } +}