contracts/lib/forge-std/test/StdUtils.t.sol 14.6 K raw
1
// SPDX-License-Identifier: MIT
2
pragma solidity >=0.7.0 <0.9.0;
3
4
import {Test, StdUtils} from "../src/Test.sol";
5
6
contract StdUtilsMock is StdUtils {
7
    // We deploy a mock version so we can properly test expected reverts.
8
    function exposed_getTokenBalances(address token, address[] memory addresses)
9
        external
10
        returns (uint256[] memory balances)
11
    {
12
        return getTokenBalances(token, addresses);
13
    }
14
15
    function exposed_bound(int256 num, int256 min, int256 max) external pure returns (int256) {
16
        return bound(num, min, max);
17
    }
18
19
    function exposed_bound(uint256 num, uint256 min, uint256 max) external pure returns (uint256) {
20
        return bound(num, min, max);
21
    }
22
23
    function exposed_bytesToUint(bytes memory b) external pure returns (uint256) {
24
        return bytesToUint(b);
25
    }
26
}
27
28
contract StdUtilsTest is Test {
29
    /*//////////////////////////////////////////////////////////////////////////
30
                                     BOUND UINT
31
    //////////////////////////////////////////////////////////////////////////*/
32
33
    function test_Bound() public pure {
34
        assertEq(bound(uint256(5), 0, 4), 0);
35
        assertEq(bound(uint256(0), 69, 69), 69);
36
        assertEq(bound(uint256(0), 68, 69), 68);
37
        assertEq(bound(uint256(10), 150, 190), 174);
38
        assertEq(bound(uint256(300), 2800, 3200), 3107);
39
        assertEq(bound(uint256(9999), 1337, 6666), 4669);
40
    }
41
42
    function test_Bound_WithinRange() public pure {
43
        assertEq(bound(uint256(51), 50, 150), 51);
44
        assertEq(bound(uint256(51), 50, 150), bound(bound(uint256(51), 50, 150), 50, 150));
45
        assertEq(bound(uint256(149), 50, 150), 149);
46
        assertEq(bound(uint256(149), 50, 150), bound(bound(uint256(149), 50, 150), 50, 150));
47
    }
48
49
    function test_Bound_EdgeCoverage() public pure {
50
        assertEq(bound(uint256(0), 50, 150), 50);
51
        assertEq(bound(uint256(1), 50, 150), 51);
52
        assertEq(bound(uint256(2), 50, 150), 52);
53
        assertEq(bound(uint256(3), 50, 150), 53);
54
        assertEq(bound(type(uint256).max, 50, 150), 150);
55
        assertEq(bound(type(uint256).max - 1, 50, 150), 149);
56
        assertEq(bound(type(uint256).max - 2, 50, 150), 148);
57
        assertEq(bound(type(uint256).max - 3, 50, 150), 147);
58
    }
59
60
    function testFuzz_Bound_DistributionIsEven(uint256 min, uint256 size) public pure {
61
        size = size % 100 + 1;
62
        min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size);
63
        uint256 max = min + size - 1;
64
        uint256 result;
65
66
        for (uint256 i = 1; i <= size * 4; ++i) {
67
            // x > max
68
            result = bound(max + i, min, max);
69
            assertEq(result, min + (i - 1) % size);
70
            // x < min
71
            result = bound(min - i, min, max);
72
            assertEq(result, max - (i - 1) % size);
73
        }
74
    }
75
76
    function testFuzz_Bound(uint256 num, uint256 min, uint256 max) public pure {
77
        if (min > max) (min, max) = (max, min);
78
79
        uint256 result = bound(num, min, max);
80
81
        assertGe(result, min);
82
        assertLe(result, max);
83
        assertEq(result, bound(result, min, max));
84
        if (num >= min && num <= max) assertEq(result, num);
85
    }
86
87
    function test_BoundUint256Max() public pure {
88
        assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1);
89
        assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max);
90
    }
91
92
    function test_RevertIf_BoundMaxLessThanMin() public {
93
        // We deploy a mock version so we can properly test the revert.
94
        StdUtilsMock stdUtils = new StdUtilsMock();
95
96
        vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min."));
97
        stdUtils.exposed_bound(uint256(5), 100, 10);
98
    }
99
100
    function testFuzz_RevertIf_BoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public {
101
        // We deploy a mock version so we can properly test the revert.
102
        StdUtilsMock stdUtils = new StdUtilsMock();
103
104
        vm.assume(min > max);
105
        vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min."));
106
        stdUtils.exposed_bound(num, min, max);
107
    }
108
109
    /*//////////////////////////////////////////////////////////////////////////
110
                                     BOUND INT
111
    //////////////////////////////////////////////////////////////////////////*/
112
113
    function test_BoundInt() public pure {
114
        assertEq(bound(-3, 0, 4), 2);
115
        assertEq(bound(0, -69, -69), -69);
116
        assertEq(bound(0, -69, -68), -68);
117
        assertEq(bound(-10, 150, 190), 154);
118
        assertEq(bound(-300, 2800, 3200), 2908);
119
        assertEq(bound(9999, -1337, 6666), 1995);
120
    }
121
122
    function test_BoundInt_WithinRange() public pure {
123
        assertEq(bound(51, -50, 150), 51);
124
        assertEq(bound(51, -50, 150), bound(bound(51, -50, 150), -50, 150));
125
        assertEq(bound(149, -50, 150), 149);
126
        assertEq(bound(149, -50, 150), bound(bound(149, -50, 150), -50, 150));
127
    }
128
129
    function test_BoundInt_EdgeCoverage() public pure {
130
        assertEq(bound(type(int256).min, -50, 150), -50);
131
        assertEq(bound(type(int256).min + 1, -50, 150), -49);
132
        assertEq(bound(type(int256).min + 2, -50, 150), -48);
133
        assertEq(bound(type(int256).min + 3, -50, 150), -47);
134
        assertEq(bound(type(int256).min, 10, 150), 10);
135
        assertEq(bound(type(int256).min + 1, 10, 150), 11);
136
        assertEq(bound(type(int256).min + 2, 10, 150), 12);
137
        assertEq(bound(type(int256).min + 3, 10, 150), 13);
138
139
        assertEq(bound(type(int256).max, -50, 150), 150);
140
        assertEq(bound(type(int256).max - 1, -50, 150), 149);
141
        assertEq(bound(type(int256).max - 2, -50, 150), 148);
142
        assertEq(bound(type(int256).max - 3, -50, 150), 147);
143
        assertEq(bound(type(int256).max, -50, -10), -10);
144
        assertEq(bound(type(int256).max - 1, -50, -10), -11);
145
        assertEq(bound(type(int256).max - 2, -50, -10), -12);
146
        assertEq(bound(type(int256).max - 3, -50, -10), -13);
147
    }
148
149
    function testFuzz_BoundInt_DistributionIsEven(int256 min, uint256 size) public pure {
150
        size = size % 100 + 1;
151
        min = bound(min, -int256(size / 2), int256(size - size / 2));
152
        int256 max = min + int256(size) - 1;
153
        int256 result;
154
155
        for (uint256 i = 1; i <= size * 4; ++i) {
156
            // x > max
157
            result = bound(max + int256(i), min, max);
158
            assertEq(result, min + int256((i - 1) % size));
159
            // x < min
160
            result = bound(min - int256(i), min, max);
161
            assertEq(result, max - int256((i - 1) % size));
162
        }
163
    }
164
165
    function testFuzz_BoundInt(int256 num, int256 min, int256 max) public pure {
166
        if (min > max) (min, max) = (max, min);
167
168
        int256 result = bound(num, min, max);
169
170
        assertGe(result, min);
171
        assertLe(result, max);
172
        assertEq(result, bound(result, min, max));
173
        if (num >= min && num <= max) assertEq(result, num);
174
    }
175
176
    function test_BoundIntInt256Max() public pure {
177
        assertEq(bound(0, type(int256).max - 1, type(int256).max), type(int256).max - 1);
178
        assertEq(bound(1, type(int256).max - 1, type(int256).max), type(int256).max);
179
    }
180
181
    function test_BoundIntInt256Min() public pure {
182
        assertEq(bound(0, type(int256).min, type(int256).min + 1), type(int256).min);
183
        assertEq(bound(1, type(int256).min, type(int256).min + 1), type(int256).min + 1);
184
    }
185
186
    function test_RevertIf_BoundIntMaxLessThanMin() public {
187
        // We deploy a mock version so we can properly test the revert.
188
        StdUtilsMock stdUtils = new StdUtilsMock();
189
190
        vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min."));
191
        stdUtils.exposed_bound(-5, 100, 10);
192
    }
193
194
    function testFuzz_RevertIf_BoundIntMaxLessThanMin(int256 num, int256 min, int256 max) public {
195
        // We deploy a mock version so we can properly test the revert.
196
        StdUtilsMock stdUtils = new StdUtilsMock();
197
198
        vm.assume(min > max);
199
        vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min."));
200
        stdUtils.exposed_bound(num, min, max);
201
    }
202
203
    /*//////////////////////////////////////////////////////////////////////////
204
                                BOUND PRIVATE KEY
205
    //////////////////////////////////////////////////////////////////////////*/
206
207
    function test_BoundPrivateKey() public pure {
208
        assertEq(boundPrivateKey(0), 1);
209
        assertEq(boundPrivateKey(1), 1);
210
        assertEq(boundPrivateKey(300), 300);
211
        assertEq(boundPrivateKey(9999), 9999);
212
        assertEq(boundPrivateKey(SECP256K1_ORDER - 1), SECP256K1_ORDER - 1);
213
        assertEq(boundPrivateKey(SECP256K1_ORDER), 1);
214
        assertEq(boundPrivateKey(SECP256K1_ORDER + 1), 2);
215
        assertEq(boundPrivateKey(UINT256_MAX), UINT256_MAX & SECP256K1_ORDER - 1); // x&y is equivalent to x-x%y
216
    }
217
218
    /*//////////////////////////////////////////////////////////////////////////
219
                                   BYTES TO UINT
220
    //////////////////////////////////////////////////////////////////////////*/
221
222
    function test_BytesToUint() external pure {
223
        bytes memory maxUint = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
224
        bytes memory two = hex"02";
225
        bytes memory millionEther = hex"d3c21bcecceda1000000";
226
227
        assertEq(bytesToUint(maxUint), type(uint256).max);
228
        assertEq(bytesToUint(two), 2);
229
        assertEq(bytesToUint(millionEther), 1_000_000 ether);
230
    }
231
232
    function test_RevertIf_BytesLengthExceeds32() external {
233
        // We deploy a mock version so we can properly test the revert.
234
        StdUtilsMock stdUtils = new StdUtilsMock();
235
236
        bytes memory thirty3Bytes = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
237
        vm.expectRevert("StdUtils bytesToUint(bytes): Bytes length exceeds 32.");
238
        stdUtils.exposed_bytesToUint(thirty3Bytes);
239
    }
240
241
    /*//////////////////////////////////////////////////////////////////////////
242
                               COMPUTE CREATE ADDRESS
243
    //////////////////////////////////////////////////////////////////////////*/
244
245
    function test_ComputeCreateAddress() external pure {
246
        address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9;
247
        uint256 nonce = 14;
248
        address createAddress = computeCreateAddress(deployer, nonce);
249
        assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45);
250
    }
251
252
    /*//////////////////////////////////////////////////////////////////////////
253
                              COMPUTE CREATE2 ADDRESS
254
    //////////////////////////////////////////////////////////////////////////*/
255
256
    function test_ComputeCreate2Address() external pure {
257
        bytes32 salt = bytes32(uint256(31415));
258
        bytes32 initcodeHash = keccak256(abi.encode(0x6080));
259
        address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9;
260
        address create2Address = computeCreate2Address(salt, initcodeHash, deployer);
261
        assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3);
262
    }
263
264
    function test_ComputeCreate2AddressWithDefaultDeployer() external pure {
265
        bytes32 salt = 0xc290c670fde54e5ef686f9132cbc8711e76a98f0333a438a92daa442c71403c0;
266
        bytes32 initcodeHash = hashInitCode(hex"6080", "");
267
        assertEq(initcodeHash, 0x1a578b7a4b0b5755db6d121b4118d4bc68fe170dca840c59bc922f14175a76b0);
268
        address create2Address = computeCreate2Address(salt, initcodeHash);
269
        assertEq(create2Address, 0xc0ffEe2198a06235aAbFffe5Db0CacF1717f5Ac6);
270
    }
271
}
272
273
contract StdUtilsForkTest is Test {
274
    /*//////////////////////////////////////////////////////////////////////////
275
                                  GET TOKEN BALANCES
276
    //////////////////////////////////////////////////////////////////////////*/
277
278
    address internal SHIB = 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE;
279
    address internal SHIB_HOLDER_0 = 0x855F5981e831D83e6A4b4EBFCAdAa68D92333170;
280
    address internal SHIB_HOLDER_1 = 0x8F509A90c2e47779cA408Fe00d7A72e359229AdA;
281
    address internal SHIB_HOLDER_2 = 0x0e3bbc0D04fF62211F71f3e4C45d82ad76224385;
282
283
    address internal USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
284
    address internal USDC_HOLDER_0 = 0xDa9CE944a37d218c3302F6B82a094844C6ECEb17;
285
    address internal USDC_HOLDER_1 = 0x3e67F4721E6d1c41a015f645eFa37BEd854fcf52;
286
287
    function setUp() public {
288
        // All tests of the `getTokenBalances` method are fork tests using live contracts.
289
        vm.createSelectFork({urlOrAlias: "mainnet", blockNumber: 16_428_900});
290
    }
291
292
    function test_RevertIf_CannotGetTokenBalances_NonTokenContract() external {
293
        // We deploy a mock version so we can properly test the revert.
294
        StdUtilsMock stdUtils = new StdUtilsMock();
295
296
        // The UniswapV2Factory contract has neither a `balanceOf` function nor a fallback function,
297
        // so the `balanceOf` call should revert.
298
        address token = address(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
299
        address[] memory addresses = new address[](1);
300
        addresses[0] = USDC_HOLDER_0;
301
302
        vm.expectRevert("Multicall3: call failed");
303
        stdUtils.exposed_getTokenBalances(token, addresses);
304
    }
305
306
    function test_RevertIf_CannotGetTokenBalances_EOA() external {
307
        // We deploy a mock version so we can properly test the revert.
308
        StdUtilsMock stdUtils = new StdUtilsMock();
309
310
        address eoa = vm.addr({privateKey: 1});
311
        address[] memory addresses = new address[](1);
312
        addresses[0] = USDC_HOLDER_0;
313
        vm.expectRevert("StdUtils getTokenBalances(address,address[]): Token address is not a contract.");
314
        stdUtils.exposed_getTokenBalances(eoa, addresses);
315
    }
316
317
    function test_GetTokenBalances_Empty() external {
318
        address[] memory addresses = new address[](0);
319
        uint256[] memory balances = getTokenBalances(USDC, addresses);
320
        assertEq(balances.length, 0);
321
    }
322
323
    function test_GetTokenBalances_USDC() external {
324
        address[] memory addresses = new address[](2);
325
        addresses[0] = USDC_HOLDER_0;
326
        addresses[1] = USDC_HOLDER_1;
327
        uint256[] memory balances = getTokenBalances(USDC, addresses);
328
        assertEq(balances[0], 159_000_000_000_000);
329
        assertEq(balances[1], 131_350_000_000_000);
330
    }
331
332
    function test_GetTokenBalances_SHIB() external {
333
        address[] memory addresses = new address[](3);
334
        addresses[0] = SHIB_HOLDER_0;
335
        addresses[1] = SHIB_HOLDER_1;
336
        addresses[2] = SHIB_HOLDER_2;
337
        uint256[] memory balances = getTokenBalances(SHIB, addresses);
338
        assertEq(balances[0], 3_323_256_285_484.42e18);
339
        assertEq(balances[1], 1_271_702_771_149.99999928e18);
340
        assertEq(balances[2], 606_357_106_247e18);
341
    }
342
}