81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| // SPDX-License-Identifier: MIT
 | |
| pragma solidity >=0.8.4;
 | |
| 
 | |
| /// @title Multicall.
 | |
| /// @notice Contract that batches view function calls and aggregates their results.
 | |
| /// @author Adapted from Makerdao's Multicall2 (https://github.com/makerdao/multicall/blob/master/src/Multicall2.sol).
 | |
| 
 | |
| contract Multicall {
 | |
|     /// @dev 0x
 | |
|     error CallFailed(string reason);
 | |
| 
 | |
|     struct Call {
 | |
|         address target;
 | |
|         bytes callData;
 | |
|     }
 | |
|     struct Result {
 | |
|         bool success;
 | |
|         bytes returnData;
 | |
|     }
 | |
| 
 | |
|     //prettier-ignore
 | |
|     constructor(/*  */) payable {/*  */}
 | |
| 
 | |
|     function mtc1(Call[] calldata calls)
 | |
|         external
 | |
|         returns (uint256, bytes[] memory)
 | |
|     {
 | |
|         uint256 bn = block.number;
 | |
|         uint256 len = calls.length;
 | |
|         bytes[] memory res = new bytes[](len);
 | |
|         uint256 j;
 | |
| 
 | |
|         while (j < len) {
 | |
|             (bool success, bytes memory ret) = calls[j]
 | |
|                 .target
 | |
|                 .call(calls[j].callData);
 | |
|             if (!success) {
 | |
|                 if (ret.length < 0x44) revert CallFailed("");
 | |
|                 assembly {
 | |
|                     ret := add(ret, 0x04)
 | |
|                 }
 | |
|                 revert CallFailed({
 | |
|                     reason: abi.decode(ret, (string))
 | |
|                 });
 | |
|             }
 | |
|             res[j] = ret;
 | |
|             ++j;
 | |
|         }
 | |
|         return (bn, res);
 | |
|     }
 | |
| 
 | |
|     function mtc2(Call[] calldata calls)
 | |
|         external
 | |
|         returns (
 | |
|             uint256,
 | |
|             bytes32,
 | |
|             Result[] memory
 | |
|         )
 | |
|     {
 | |
|         uint256 bn = block.number;
 | |
|         // µ 0 s [0] ≡ P(IHp , µs [0], 0) ∴ P is the hash of a block of a particular number, up to a maximum age.
 | |
|         // 0 is left on the stack if the looked for `block.number` is >= to the current `block.number` or more than 256
 | |
|         // blocks behind the current block (Yellow Paper, p. 33, https://ethereum.github.io/yellowpaper/paper.pdf).
 | |
|         bytes32 bh = blockhash(
 | |
|             bn /* - 1 */
 | |
|         );
 | |
|         uint256 len = calls.length;
 | |
|         Result[] memory res = new Result[](len);
 | |
|         uint256 i;
 | |
|         for (i; i < len; ) {
 | |
|             (bool success, bytes memory ret) = calls[i]
 | |
|                 .target
 | |
|                 .call(calls[i].callData);
 | |
| 
 | |
|             res[i] = Result(success, ret);
 | |
|             ++i;
 | |
|         }
 | |
|         return (bn, bh, res);
 | |
|     }
 | |
| }
 |