poseidon-solidity-example/lib/forge-std/src/StdUtils.sol
lib/forge-std/src/StdUtils.solRaw
1// SPDX-License-Identifier: MIT
2pragma solidity >=0.6.2 <0.9.0;
3
4pragma experimental ABIEncoderV2;
5
6import {IMulticall3} from "./interfaces/IMulticall3.sol";
7// TODO Remove import.
8import {VmSafe} from "./Vm.sol";
9
10abstract contract StdUtils {
11 /*//////////////////////////////////////////////////////////////////////////
12 CONSTANTS
13 //////////////////////////////////////////////////////////////////////////*/
14
15 IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11);
16 VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
17 address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67;
18 uint256 private constant INT256_MIN_ABS =
19 57896044618658097711785492504343953926634992332820282019728792003956564819968;
20 uint256 private constant UINT256_MAX =
21 115792089237316195423570985008687907853269984665640564039457584007913129639935;
22
23 /*//////////////////////////////////////////////////////////////////////////
24 INTERNAL FUNCTIONS
25 //////////////////////////////////////////////////////////////////////////*/
26
27 function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {
28 require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min.");
29 // If x is between min and max, return x directly. This is to ensure that dictionary values
30 // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188
31 if (x >= min && x <= max) return x;
32
33 uint256 size = max - min + 1;
34
35 // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side.
36 // This helps ensure coverage of the min/max values.
37 if (x <= 3 && size > x) return min + x;
38 if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x);
39
40 // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive.
41 if (x > max) {
42 uint256 diff = x - max;
43 uint256 rem = diff % size;
44 if (rem == 0) return max;
45 result = min + rem - 1;
46 } else if (x < min) {
47 uint256 diff = min - x;
48 uint256 rem = diff % size;
49 if (rem == 0) return min;
50 result = max - rem + 1;
51 }
52 }
53
54 function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) {
55 result = _bound(x, min, max);
56 console2_log("Bound Result", result);
57 }
58
59 function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) {
60 require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min.");
61
62 // Shifting all int256 values to uint256 to use _bound function. The range of two types are:
63 // int256 : -(2**255) ~ (2**255 - 1)
64 // uint256: 0 ~ (2**256 - 1)
65 // So, add 2**255, INT256_MIN_ABS to the integer values.
66 //
67 // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow.
68 // So, use `~uint256(x) + 1` instead.
69 uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS);
70 uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS);
71 uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS);
72
73 uint256 y = _bound(_x, _min, _max);
74
75 // To move it back to int256 value, subtract INT256_MIN_ABS at here.
76 result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS);
77 console2_log("Bound result", vm.toString(result));
78 }
79
80 function bytesToUint(bytes memory b) internal pure virtual returns (uint256) {
81 require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32.");
82 return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));
83 }
84
85 /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce
86 /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol)
87 function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) {
88 // forgefmt: disable-start
89 // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0.
90 // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it.
91 if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80))));
92 if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce))));
93
94 // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length.
95 if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce))));
96 if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce))));
97 if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce))));
98 // forgefmt: disable-end
99
100 // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp
101 // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce)
102 // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)
103 // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex)
104 // We assume nobody can have a nonce large enough to require more than 32 bytes.
105 return addressFromLast20Bytes(
106 keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce)))
107 );
108 }
109
110 function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer)
111 internal
112 pure
113 virtual
114 returns (address)
115 {
116 return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash)));
117 }
118
119 // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses.
120 function getTokenBalances(address token, address[] memory addresses)
121 internal
122 virtual
123 returns (uint256[] memory balances)
124 {
125 uint256 tokenCodeSize;
126 assembly {
127 tokenCodeSize := extcodesize(token)
128 }
129 require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract.");
130
131 // ABI encode the aggregate call to Multicall3.
132 uint256 length = addresses.length;
133 IMulticall3.Call[] memory calls = new IMulticall3.Call[](length);
134 for (uint256 i = 0; i < length; ++i) {
135 // 0x70a08231 = bytes4("balanceOf(address)"))
136 calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))});
137 }
138
139 // Make the aggregate call.
140 (, bytes[] memory returnData) = multicall.aggregate(calls);
141
142 // ABI decode the return data and return the balances.
143 balances = new uint256[](length);
144 for (uint256 i = 0; i < length; ++i) {
145 balances[i] = abi.decode(returnData[i], (uint256));
146 }
147 }
148
149 /*//////////////////////////////////////////////////////////////////////////
150 PRIVATE FUNCTIONS
151 //////////////////////////////////////////////////////////////////////////*/
152
153 function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) {
154 return address(uint160(uint256(bytesValue)));
155 }
156
157 // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere.
158
159 function console2_log(string memory p0, uint256 p1) private view {
160 (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1));
161 status;
162 }
163
164 function console2_log(string memory p0, string memory p1) private view {
165 (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1));
166 status;
167 }
168}