| 1 | // SPDX-License-Identifier: MIT |
| 2 | pragma solidity >=0.6.2 <0.9.0; |
| 3 | |
| 4 | pragma experimental ABIEncoderV2; |
| 5 | |
| 6 | import {IMulticall3} from "./interfaces/IMulticall3.sol"; |
| 7 | import {VmSafe} from "./Vm.sol"; |
| 8 | |
| 9 | abstract contract StdUtils { |
| 10 | /*////////////////////////////////////////////////////////////////////////// |
| 11 | CONSTANTS |
| 12 | //////////////////////////////////////////////////////////////////////////*/ |
| 13 | |
| 14 | IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11); |
| 15 | VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); |
| 16 | address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; |
| 17 | uint256 private constant INT256_MIN_ABS = |
| 18 | 57896044618658097711785492504343953926634992332820282019728792003956564819968; |
| 19 | uint256 private constant SECP256K1_ORDER = |
| 20 | 115792089237316195423570985008687907852837564279074904382605163141518161494337; |
| 21 | uint256 private constant UINT256_MAX = |
| 22 | 115792089237316195423570985008687907853269984665640564039457584007913129639935; |
| 23 | |
| 24 | // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. |
| 25 | address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; |
| 26 | |
| 27 | /*////////////////////////////////////////////////////////////////////////// |
| 28 | INTERNAL FUNCTIONS |
| 29 | //////////////////////////////////////////////////////////////////////////*/ |
| 30 | |
| 31 | function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { |
| 32 | require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); |
| 33 | // If x is between min and max, return x directly. This is to ensure that dictionary values |
| 34 | // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 |
| 35 | if (x >= min && x <= max) return x; |
| 36 | |
| 37 | uint256 size = max - min + 1; |
| 38 | |
| 39 | // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. |
| 40 | // This helps ensure coverage of the min/max values. |
| 41 | if (x <= 3 && size > x) return min + x; |
| 42 | if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); |
| 43 | |
| 44 | // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. |
| 45 | if (x > max) { |
| 46 | uint256 diff = x - max; |
| 47 | uint256 rem = diff % size; |
| 48 | if (rem == 0) return max; |
| 49 | result = min + rem - 1; |
| 50 | } else if (x < min) { |
| 51 | uint256 diff = min - x; |
| 52 | uint256 rem = diff % size; |
| 53 | if (rem == 0) return min; |
| 54 | result = max - rem + 1; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | function bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { |
| 59 | result = _bound(x, min, max); |
| 60 | console2_log_StdUtils("Bound result", result); |
| 61 | } |
| 62 | |
| 63 | function _bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) { |
| 64 | require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); |
| 65 | |
| 66 | // Shifting all int256 values to uint256 to use _bound function. The range of two types are: |
| 67 | // int256 : -(2**255) ~ (2**255 - 1) |
| 68 | // uint256: 0 ~ (2**256 - 1) |
| 69 | // So, add 2**255, INT256_MIN_ABS to the integer values. |
| 70 | // |
| 71 | // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. |
| 72 | // So, use `~uint256(x) + 1` instead. |
| 73 | uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); |
| 74 | uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); |
| 75 | uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); |
| 76 | |
| 77 | uint256 y = _bound(_x, _min, _max); |
| 78 | |
| 79 | // To move it back to int256 value, subtract INT256_MIN_ABS at here. |
| 80 | result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); |
| 81 | } |
| 82 | |
| 83 | function bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) { |
| 84 | result = _bound(x, min, max); |
| 85 | console2_log_StdUtils("Bound result", vm.toString(result)); |
| 86 | } |
| 87 | |
| 88 | function boundPrivateKey(uint256 privateKey) internal pure virtual returns (uint256 result) { |
| 89 | result = _bound(privateKey, 1, SECP256K1_ORDER - 1); |
| 90 | } |
| 91 | |
| 92 | function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { |
| 93 | require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); |
| 94 | return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); |
| 95 | } |
| 96 | |
| 97 | /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce |
| 98 | /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) |
| 99 | function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { |
| 100 | console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead."); |
| 101 | return vm.computeCreateAddress(deployer, nonce); |
| 102 | } |
| 103 | |
| 104 | function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) |
| 105 | internal |
| 106 | pure |
| 107 | virtual |
| 108 | returns (address) |
| 109 | { |
| 110 | console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); |
| 111 | return vm.computeCreate2Address(salt, initcodeHash, deployer); |
| 112 | } |
| 113 | |
| 114 | /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer |
| 115 | function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) { |
| 116 | console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead."); |
| 117 | return vm.computeCreate2Address(salt, initCodeHash); |
| 118 | } |
| 119 | |
| 120 | /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments |
| 121 | /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode |
| 122 | function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) { |
| 123 | return hashInitCode(creationCode, ""); |
| 124 | } |
| 125 | |
| 126 | /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2 |
| 127 | /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode |
| 128 | /// @param args the ABI-encoded arguments to the constructor of C |
| 129 | function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) { |
| 130 | return keccak256(abi.encodePacked(creationCode, args)); |
| 131 | } |
| 132 | |
| 133 | // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses. |
| 134 | function getTokenBalances(address token, address[] memory addresses) |
| 135 | internal |
| 136 | virtual |
| 137 | returns (uint256[] memory balances) |
| 138 | { |
| 139 | uint256 tokenCodeSize; |
| 140 | assembly { |
| 141 | tokenCodeSize := extcodesize(token) |
| 142 | } |
| 143 | require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract."); |
| 144 | |
| 145 | // ABI encode the aggregate call to Multicall3. |
| 146 | uint256 length = addresses.length; |
| 147 | IMulticall3.Call[] memory calls = new IMulticall3.Call[](length); |
| 148 | for (uint256 i = 0; i < length; ++i) { |
| 149 | // 0x70a08231 = bytes4("balanceOf(address)")) |
| 150 | calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))}); |
| 151 | } |
| 152 | |
| 153 | // Make the aggregate call. |
| 154 | (, bytes[] memory returnData) = multicall.aggregate(calls); |
| 155 | |
| 156 | // ABI decode the return data and return the balances. |
| 157 | balances = new uint256[](length); |
| 158 | for (uint256 i = 0; i < length; ++i) { |
| 159 | balances[i] = abi.decode(returnData[i], (uint256)); |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | /*////////////////////////////////////////////////////////////////////////// |
| 164 | PRIVATE FUNCTIONS |
| 165 | //////////////////////////////////////////////////////////////////////////*/ |
| 166 | |
| 167 | function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { |
| 168 | return address(uint160(uint256(bytesValue))); |
| 169 | } |
| 170 | |
| 171 | // This section is used to prevent the compilation of console, which shortens the compilation time when console is |
| 172 | // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid |
| 173 | // any breaking changes to function signatures. |
| 174 | function _castLogPayloadViewToPure(function(bytes memory) internal view fnIn) |
| 175 | internal |
| 176 | pure |
| 177 | returns (function(bytes memory) internal pure fnOut) |
| 178 | { |
| 179 | assembly { |
| 180 | fnOut := fnIn |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | function _sendLogPayload(bytes memory payload) internal pure { |
| 185 | _castLogPayloadViewToPure(_sendLogPayloadView)(payload); |
| 186 | } |
| 187 | |
| 188 | function _sendLogPayloadView(bytes memory payload) private view { |
| 189 | uint256 payloadLength = payload.length; |
| 190 | address consoleAddress = CONSOLE2_ADDRESS; |
| 191 | /// @solidity memory-safe-assembly |
| 192 | assembly { |
| 193 | let payloadStart := add(payload, 32) |
| 194 | let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | function console2_log_StdUtils(string memory p0) private pure { |
| 199 | _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); |
| 200 | } |
| 201 | |
| 202 | function console2_log_StdUtils(string memory p0, uint256 p1) private pure { |
| 203 | _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); |
| 204 | } |
| 205 | |
| 206 | function console2_log_StdUtils(string memory p0, string memory p1) private pure { |
| 207 | _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); |
| 208 | } |
| 209 | } |