@bgd-labs/aave-address-book 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitmodules +4 -0
- package/CHANGELOG.md +56 -0
- package/LICENSE +7 -0
- package/README.md +94 -0
- package/addressbook_logo.png +0 -0
- package/dist/AaveAddressBook.d.ts +17 -0
- package/dist/AaveAddressBook.js +20 -0
- package/dist/AaveV2Avalanche.d.ts +9 -0
- package/dist/AaveV2Avalanche.js +12 -0
- package/dist/AaveV2Ethereum.d.ts +9 -0
- package/dist/AaveV2Ethereum.js +12 -0
- package/dist/AaveV2EthereumAMM.d.ts +9 -0
- package/dist/AaveV2EthereumAMM.js +12 -0
- package/dist/AaveV2EthereumArc.d.ts +9 -0
- package/dist/AaveV2EthereumArc.js +12 -0
- package/dist/AaveV2Fuji.d.ts +9 -0
- package/dist/AaveV2Fuji.js +12 -0
- package/dist/AaveV2Mumbai.d.ts +9 -0
- package/dist/AaveV2Mumbai.js +12 -0
- package/dist/AaveV2Polygon.d.ts +9 -0
- package/dist/AaveV2Polygon.js +12 -0
- package/dist/AaveV3Arbitrum.d.ts +9 -0
- package/dist/AaveV3Arbitrum.js +12 -0
- package/dist/AaveV3Avalanche.d.ts +9 -0
- package/dist/AaveV3Avalanche.js +12 -0
- package/dist/AaveV3Fantom.d.ts +9 -0
- package/dist/AaveV3Fantom.js +12 -0
- package/dist/AaveV3FantomTestnet.d.ts +9 -0
- package/dist/AaveV3FantomTestnet.js +12 -0
- package/dist/AaveV3Fuji.d.ts +9 -0
- package/dist/AaveV3Fuji.js +12 -0
- package/dist/AaveV3Harmony.d.ts +9 -0
- package/dist/AaveV3Harmony.js +12 -0
- package/dist/AaveV3Mumbai.d.ts +9 -0
- package/dist/AaveV3Mumbai.js +12 -0
- package/dist/AaveV3Optimism.d.ts +9 -0
- package/dist/AaveV3Optimism.js +12 -0
- package/dist/AaveV3OptimismKovan.d.ts +9 -0
- package/dist/AaveV3OptimismKovan.js +12 -0
- package/dist/AaveV3Polygon.d.ts +9 -0
- package/dist/AaveV3Polygon.js +12 -0
- package/foundry.toml +8 -0
- package/lib/forge-std/.github/workflows/tests.yml +27 -0
- package/lib/forge-std/.gitmodules +3 -0
- package/lib/forge-std/LICENSE-APACHE +203 -0
- package/lib/forge-std/LICENSE-MIT +25 -0
- package/lib/forge-std/README.md +246 -0
- package/lib/forge-std/lib/ds-test/LICENSE +674 -0
- package/lib/forge-std/lib/ds-test/Makefile +14 -0
- package/lib/forge-std/lib/ds-test/default.nix +4 -0
- package/lib/forge-std/lib/ds-test/demo/demo.sol +222 -0
- package/lib/forge-std/lib/ds-test/src/test.sol +469 -0
- package/lib/forge-std/src/Script.sol +39 -0
- package/lib/forge-std/src/StdJson.sol +118 -0
- package/lib/forge-std/src/Test.sol +1134 -0
- package/lib/forge-std/src/Vm.sol +231 -0
- package/lib/forge-std/src/console.sol +1533 -0
- package/lib/forge-std/src/console2.sol +1538 -0
- package/lib/forge-std/src/test/Script.t.sol +12 -0
- package/lib/forge-std/src/test/StdAssertions.t.sol +591 -0
- package/lib/forge-std/src/test/StdCheats.t.sol +282 -0
- package/lib/forge-std/src/test/StdError.t.sol +124 -0
- package/lib/forge-std/src/test/StdMath.t.sol +200 -0
- package/lib/forge-std/src/test/StdStorage.t.sol +321 -0
- package/lib/forge-std/src/test/fixtures/broadcast.log.json +187 -0
- package/package.json +39 -0
- package/src/AaveAddressBook.sol +28 -0
- package/src/AaveAddressBookV2.sol +143 -0
- package/src/AaveAddressBookV2Testnet.sol +74 -0
- package/src/AaveAddressBookV3.sol +166 -0
- package/src/AaveAddressBookV3Testnet.sol +120 -0
- package/src/AaveGovernanceV2.sol +549 -0
- package/src/AaveV2.sol +931 -0
- package/src/AaveV2Avalanche.sol +35 -0
- package/src/AaveV2Ethereum.sol +36 -0
- package/src/AaveV2EthereumAMM.sol +36 -0
- package/src/AaveV2EthereumArc.sol +36 -0
- package/src/AaveV2Fuji.sol +35 -0
- package/src/AaveV2Mumbai.sol +35 -0
- package/src/AaveV2Polygon.sol +35 -0
- package/src/AaveV3.sol +2406 -0
- package/src/AaveV3Arbitrum.sol +34 -0
- package/src/AaveV3Avalanche.sol +34 -0
- package/src/AaveV3Fantom.sol +34 -0
- package/src/AaveV3FantomTestnet.sol +34 -0
- package/src/AaveV3Fuji.sol +34 -0
- package/src/AaveV3Harmony.sol +34 -0
- package/src/AaveV3HarmonyTestnet.sol +34 -0
- package/src/AaveV3Mumbai.sol +34 -0
- package/src/AaveV3Optimism.sol +34 -0
- package/src/AaveV3OptimismKovan.sol +34 -0
- package/src/AaveV3Polygon.sol +34 -0
- package/src/Common.sol +9 -0
- package/src/test/AaveV2Ethereum.t.sol +72 -0
- package/src/test/AaveV2Misfits.t.sol +33 -0
- package/src/test/AaveV3Avalanche.t.sol +65 -0
- package/src/ts/AaveAddressBook.ts +17 -0
- package/src/ts/AaveV2Avalanche.ts +11 -0
- package/src/ts/AaveV2Ethereum.ts +12 -0
- package/src/ts/AaveV2EthereumAMM.ts +12 -0
- package/src/ts/AaveV2EthereumArc.ts +12 -0
- package/src/ts/AaveV2Fuji.ts +11 -0
- package/src/ts/AaveV2Mumbai.ts +11 -0
- package/src/ts/AaveV2Polygon.ts +11 -0
- package/src/ts/AaveV3Arbitrum.ts +12 -0
- package/src/ts/AaveV3Avalanche.ts +12 -0
- package/src/ts/AaveV3Fantom.ts +12 -0
- package/src/ts/AaveV3FantomTestnet.ts +12 -0
- package/src/ts/AaveV3Fuji.ts +12 -0
- package/src/ts/AaveV3Harmony.ts +12 -0
- package/src/ts/AaveV3Mumbai.ts +12 -0
- package/src/ts/AaveV3Optimism.ts +12 -0
- package/src/ts/AaveV3OptimismKovan.ts +12 -0
- package/src/ts/AaveV3Polygon.ts +12 -0
- package/tsconfig.json +101 -0
|
@@ -0,0 +1,1134 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity >=0.6.0 <0.9.0;
|
|
3
|
+
pragma experimental ABIEncoderV2;
|
|
4
|
+
|
|
5
|
+
import "./Script.sol";
|
|
6
|
+
import "ds-test/test.sol";
|
|
7
|
+
|
|
8
|
+
// Wrappers around Cheatcodes to avoid footguns
|
|
9
|
+
abstract contract Test is DSTest, Script {
|
|
10
|
+
using stdStorage for StdStorage;
|
|
11
|
+
|
|
12
|
+
uint256 internal constant UINT256_MAX =
|
|
13
|
+
115792089237316195423570985008687907853269984665640564039457584007913129639935;
|
|
14
|
+
|
|
15
|
+
StdStorage internal stdstore;
|
|
16
|
+
|
|
17
|
+
/*//////////////////////////////////////////////////////////////////////////
|
|
18
|
+
STD-LOGS
|
|
19
|
+
//////////////////////////////////////////////////////////////////////////*/
|
|
20
|
+
|
|
21
|
+
event log_array(uint256[] val);
|
|
22
|
+
event log_array(int256[] val);
|
|
23
|
+
event log_array(address[] val);
|
|
24
|
+
event log_named_array(string key, uint256[] val);
|
|
25
|
+
event log_named_array(string key, int256[] val);
|
|
26
|
+
event log_named_array(string key, address[] val);
|
|
27
|
+
|
|
28
|
+
/*//////////////////////////////////////////////////////////////////////////
|
|
29
|
+
STD-CHEATS
|
|
30
|
+
//////////////////////////////////////////////////////////////////////////*/
|
|
31
|
+
|
|
32
|
+
// Skip forward or rewind time by the specified number of seconds
|
|
33
|
+
function skip(uint256 time) internal {
|
|
34
|
+
vm.warp(block.timestamp + time);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function rewind(uint256 time) internal {
|
|
38
|
+
vm.warp(block.timestamp - time);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Setup a prank from an address that has some ether
|
|
42
|
+
function hoax(address who) internal {
|
|
43
|
+
vm.deal(who, 1 << 128);
|
|
44
|
+
vm.prank(who);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function hoax(address who, uint256 give) internal {
|
|
48
|
+
vm.deal(who, give);
|
|
49
|
+
vm.prank(who);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function hoax(address who, address origin) internal {
|
|
53
|
+
vm.deal(who, 1 << 128);
|
|
54
|
+
vm.prank(who, origin);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function hoax(address who, address origin, uint256 give) internal {
|
|
58
|
+
vm.deal(who, give);
|
|
59
|
+
vm.prank(who, origin);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Start perpetual prank from an address that has some ether
|
|
63
|
+
function startHoax(address who) internal {
|
|
64
|
+
vm.deal(who, 1 << 128);
|
|
65
|
+
vm.startPrank(who);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function startHoax(address who, uint256 give) internal {
|
|
69
|
+
vm.deal(who, give);
|
|
70
|
+
vm.startPrank(who);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Start perpetual prank from an address that has some ether
|
|
74
|
+
// tx.origin is set to the origin parameter
|
|
75
|
+
function startHoax(address who, address origin) internal {
|
|
76
|
+
vm.deal(who, 1 << 128);
|
|
77
|
+
vm.startPrank(who, origin);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function startHoax(address who, address origin, uint256 give) internal {
|
|
81
|
+
vm.deal(who, give);
|
|
82
|
+
vm.startPrank(who, origin);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function changePrank(address who) internal {
|
|
86
|
+
vm.stopPrank();
|
|
87
|
+
vm.startPrank(who);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// creates a labeled address and the corresponding private key
|
|
91
|
+
function makeAddrAndKey(string memory name) internal returns(address addr, uint256 privateKey) {
|
|
92
|
+
privateKey = uint256(keccak256(abi.encodePacked(name)));
|
|
93
|
+
addr = vm.addr(privateKey);
|
|
94
|
+
vm.label(addr, name);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// creates a labeled address
|
|
98
|
+
function makeAddr(string memory name) internal returns(address addr) {
|
|
99
|
+
(addr,) = makeAddrAndKey(name);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// DEPRECATED: Use `deal` instead
|
|
103
|
+
function tip(address token, address to, uint256 give) internal {
|
|
104
|
+
emit log_named_string("WARNING", "Test tip(address,address,uint256): The `tip` stdcheat has been deprecated. Use `deal` instead.");
|
|
105
|
+
stdstore
|
|
106
|
+
.target(token)
|
|
107
|
+
.sig(0x70a08231)
|
|
108
|
+
.with_key(to)
|
|
109
|
+
.checked_write(give);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// The same as Vm's `deal`
|
|
113
|
+
// Use the alternative signature for ERC20 tokens
|
|
114
|
+
function deal(address to, uint256 give) internal {
|
|
115
|
+
vm.deal(to, give);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Set the balance of an account for any ERC20 token
|
|
119
|
+
// Use the alternative signature to update `totalSupply`
|
|
120
|
+
function deal(address token, address to, uint256 give) internal {
|
|
121
|
+
deal(token, to, give, false);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function deal(address token, address to, uint256 give, bool adjust) internal {
|
|
125
|
+
// get current balance
|
|
126
|
+
(, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to));
|
|
127
|
+
uint256 prevBal = abi.decode(balData, (uint256));
|
|
128
|
+
|
|
129
|
+
// update balance
|
|
130
|
+
stdstore
|
|
131
|
+
.target(token)
|
|
132
|
+
.sig(0x70a08231)
|
|
133
|
+
.with_key(to)
|
|
134
|
+
.checked_write(give);
|
|
135
|
+
|
|
136
|
+
// update total supply
|
|
137
|
+
if(adjust){
|
|
138
|
+
(, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd));
|
|
139
|
+
uint256 totSup = abi.decode(totSupData, (uint256));
|
|
140
|
+
if(give < prevBal) {
|
|
141
|
+
totSup -= (prevBal - give);
|
|
142
|
+
} else {
|
|
143
|
+
totSup += (give - prevBal);
|
|
144
|
+
}
|
|
145
|
+
stdstore
|
|
146
|
+
.target(token)
|
|
147
|
+
.sig(0x18160ddd)
|
|
148
|
+
.checked_write(totSup);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function bound(uint256 x, uint256 min, uint256 max) internal virtual returns (uint256 result) {
|
|
153
|
+
require(min <= max, "Test bound(uint256,uint256,uint256): Max is less than min.");
|
|
154
|
+
|
|
155
|
+
uint256 size = max - min;
|
|
156
|
+
|
|
157
|
+
if (size == 0)
|
|
158
|
+
{
|
|
159
|
+
result = min;
|
|
160
|
+
}
|
|
161
|
+
else if (size == UINT256_MAX)
|
|
162
|
+
{
|
|
163
|
+
result = x;
|
|
164
|
+
}
|
|
165
|
+
else
|
|
166
|
+
{
|
|
167
|
+
++size; // make `max` inclusive
|
|
168
|
+
uint256 mod = x % size;
|
|
169
|
+
result = min + mod;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
emit log_named_uint("Bound Result", result);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Deploy a contract by fetching the contract bytecode from
|
|
176
|
+
// the artifacts directory
|
|
177
|
+
// e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))`
|
|
178
|
+
function deployCode(string memory what, bytes memory args)
|
|
179
|
+
internal
|
|
180
|
+
returns (address addr)
|
|
181
|
+
{
|
|
182
|
+
bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
|
|
183
|
+
/// @solidity memory-safe-assembly
|
|
184
|
+
assembly {
|
|
185
|
+
addr := create(0, add(bytecode, 0x20), mload(bytecode))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
require(
|
|
189
|
+
addr != address(0),
|
|
190
|
+
"Test deployCode(string,bytes): Deployment failed."
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function deployCode(string memory what)
|
|
195
|
+
internal
|
|
196
|
+
returns (address addr)
|
|
197
|
+
{
|
|
198
|
+
bytes memory bytecode = vm.getCode(what);
|
|
199
|
+
/// @solidity memory-safe-assembly
|
|
200
|
+
assembly {
|
|
201
|
+
addr := create(0, add(bytecode, 0x20), mload(bytecode))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
require(
|
|
205
|
+
addr != address(0),
|
|
206
|
+
"Test deployCode(string): Deployment failed."
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/// deploy contract with value on construction
|
|
211
|
+
function deployCode(string memory what, bytes memory args, uint256 val)
|
|
212
|
+
internal
|
|
213
|
+
returns (address addr)
|
|
214
|
+
{
|
|
215
|
+
bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
|
|
216
|
+
/// @solidity memory-safe-assembly
|
|
217
|
+
assembly {
|
|
218
|
+
addr := create(val, add(bytecode, 0x20), mload(bytecode))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
require(
|
|
222
|
+
addr != address(0),
|
|
223
|
+
"Test deployCode(string,bytes,uint256): Deployment failed."
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function deployCode(string memory what, uint256 val)
|
|
228
|
+
internal
|
|
229
|
+
returns (address addr)
|
|
230
|
+
{
|
|
231
|
+
bytes memory bytecode = vm.getCode(what);
|
|
232
|
+
/// @solidity memory-safe-assembly
|
|
233
|
+
assembly {
|
|
234
|
+
addr := create(val, add(bytecode, 0x20), mload(bytecode))
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
require(
|
|
238
|
+
addr != address(0),
|
|
239
|
+
"Test deployCode(string,uint256): Deployment failed."
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/*//////////////////////////////////////////////////////////////////////////
|
|
244
|
+
STD-ASSERTIONS
|
|
245
|
+
//////////////////////////////////////////////////////////////////////////*/
|
|
246
|
+
|
|
247
|
+
function fail(string memory err) internal virtual {
|
|
248
|
+
emit log_named_string("Error", err);
|
|
249
|
+
fail();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function assertFalse(bool data) internal virtual {
|
|
253
|
+
assertTrue(!data);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function assertFalse(bool data, string memory err) internal virtual {
|
|
257
|
+
assertTrue(!data, err);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function assertEq(bool a, bool b) internal {
|
|
261
|
+
if (a != b) {
|
|
262
|
+
emit log ("Error: a == b not satisfied [bool]");
|
|
263
|
+
emit log_named_string (" Expected", b ? "true" : "false");
|
|
264
|
+
emit log_named_string (" Actual", a ? "true" : "false");
|
|
265
|
+
fail();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function assertEq(bool a, bool b, string memory err) internal {
|
|
270
|
+
if (a != b) {
|
|
271
|
+
emit log_named_string("Error", err);
|
|
272
|
+
assertEq(a, b);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function assertEq(bytes memory a, bytes memory b) internal {
|
|
277
|
+
assertEq0(a, b);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function assertEq(bytes memory a, bytes memory b, string memory err) internal {
|
|
281
|
+
assertEq0(a, b, err);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function assertEq(uint256[] memory a, uint256[] memory b) internal {
|
|
285
|
+
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
|
|
286
|
+
emit log("Error: a == b not satisfied [uint[]]");
|
|
287
|
+
emit log_named_array(" Expected", b);
|
|
288
|
+
emit log_named_array(" Actual", a);
|
|
289
|
+
fail();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function assertEq(int256[] memory a, int256[] memory b) internal {
|
|
294
|
+
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
|
|
295
|
+
emit log("Error: a == b not satisfied [int[]]");
|
|
296
|
+
emit log_named_array(" Expected", b);
|
|
297
|
+
emit log_named_array(" Actual", a);
|
|
298
|
+
fail();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function assertEq(address[] memory a, address[] memory b) internal {
|
|
303
|
+
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
|
|
304
|
+
emit log("Error: a == b not satisfied [address[]]");
|
|
305
|
+
emit log_named_array(" Expected", b);
|
|
306
|
+
emit log_named_array(" Actual", a);
|
|
307
|
+
fail();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal {
|
|
312
|
+
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
|
|
313
|
+
emit log_named_string("Error", err);
|
|
314
|
+
assertEq(a, b);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function assertEq(int256[] memory a, int256[] memory b, string memory err) internal {
|
|
319
|
+
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
|
|
320
|
+
emit log_named_string("Error", err);
|
|
321
|
+
assertEq(a, b);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
function assertEq(address[] memory a, address[] memory b, string memory err) internal {
|
|
327
|
+
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
|
|
328
|
+
emit log_named_string("Error", err);
|
|
329
|
+
assertEq(a, b);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function assertApproxEqAbs(
|
|
334
|
+
uint256 a,
|
|
335
|
+
uint256 b,
|
|
336
|
+
uint256 maxDelta
|
|
337
|
+
) internal virtual {
|
|
338
|
+
uint256 delta = stdMath.delta(a, b);
|
|
339
|
+
|
|
340
|
+
if (delta > maxDelta) {
|
|
341
|
+
emit log ("Error: a ~= b not satisfied [uint]");
|
|
342
|
+
emit log_named_uint (" Expected", b);
|
|
343
|
+
emit log_named_uint (" Actual", a);
|
|
344
|
+
emit log_named_uint (" Max Delta", maxDelta);
|
|
345
|
+
emit log_named_uint (" Delta", delta);
|
|
346
|
+
fail();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function assertApproxEqAbs(
|
|
351
|
+
uint256 a,
|
|
352
|
+
uint256 b,
|
|
353
|
+
uint256 maxDelta,
|
|
354
|
+
string memory err
|
|
355
|
+
) internal virtual {
|
|
356
|
+
uint256 delta = stdMath.delta(a, b);
|
|
357
|
+
|
|
358
|
+
if (delta > maxDelta) {
|
|
359
|
+
emit log_named_string ("Error", err);
|
|
360
|
+
assertApproxEqAbs(a, b, maxDelta);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function assertApproxEqAbs(
|
|
365
|
+
int256 a,
|
|
366
|
+
int256 b,
|
|
367
|
+
uint256 maxDelta
|
|
368
|
+
) internal virtual {
|
|
369
|
+
uint256 delta = stdMath.delta(a, b);
|
|
370
|
+
|
|
371
|
+
if (delta > maxDelta) {
|
|
372
|
+
emit log ("Error: a ~= b not satisfied [int]");
|
|
373
|
+
emit log_named_int (" Expected", b);
|
|
374
|
+
emit log_named_int (" Actual", a);
|
|
375
|
+
emit log_named_uint (" Max Delta", maxDelta);
|
|
376
|
+
emit log_named_uint (" Delta", delta);
|
|
377
|
+
fail();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function assertApproxEqAbs(
|
|
382
|
+
int256 a,
|
|
383
|
+
int256 b,
|
|
384
|
+
uint256 maxDelta,
|
|
385
|
+
string memory err
|
|
386
|
+
) internal virtual {
|
|
387
|
+
uint256 delta = stdMath.delta(a, b);
|
|
388
|
+
|
|
389
|
+
if (delta > maxDelta) {
|
|
390
|
+
emit log_named_string ("Error", err);
|
|
391
|
+
assertApproxEqAbs(a, b, maxDelta);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function assertApproxEqRel(
|
|
396
|
+
uint256 a,
|
|
397
|
+
uint256 b,
|
|
398
|
+
uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100%
|
|
399
|
+
) internal virtual {
|
|
400
|
+
if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.
|
|
401
|
+
|
|
402
|
+
uint256 percentDelta = stdMath.percentDelta(a, b);
|
|
403
|
+
|
|
404
|
+
if (percentDelta > maxPercentDelta) {
|
|
405
|
+
emit log ("Error: a ~= b not satisfied [uint]");
|
|
406
|
+
emit log_named_uint (" Expected", b);
|
|
407
|
+
emit log_named_uint (" Actual", a);
|
|
408
|
+
emit log_named_decimal_uint (" Max % Delta", maxPercentDelta, 18);
|
|
409
|
+
emit log_named_decimal_uint (" % Delta", percentDelta, 18);
|
|
410
|
+
fail();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function assertApproxEqRel(
|
|
415
|
+
uint256 a,
|
|
416
|
+
uint256 b,
|
|
417
|
+
uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
|
|
418
|
+
string memory err
|
|
419
|
+
) internal virtual {
|
|
420
|
+
if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too.
|
|
421
|
+
|
|
422
|
+
uint256 percentDelta = stdMath.percentDelta(a, b);
|
|
423
|
+
|
|
424
|
+
if (percentDelta > maxPercentDelta) {
|
|
425
|
+
emit log_named_string ("Error", err);
|
|
426
|
+
assertApproxEqRel(a, b, maxPercentDelta);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function assertApproxEqRel(
|
|
431
|
+
int256 a,
|
|
432
|
+
int256 b,
|
|
433
|
+
uint256 maxPercentDelta
|
|
434
|
+
) internal virtual {
|
|
435
|
+
if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.
|
|
436
|
+
|
|
437
|
+
uint256 percentDelta = stdMath.percentDelta(a, b);
|
|
438
|
+
|
|
439
|
+
if (percentDelta > maxPercentDelta) {
|
|
440
|
+
emit log ("Error: a ~= b not satisfied [int]");
|
|
441
|
+
emit log_named_int (" Expected", b);
|
|
442
|
+
emit log_named_int (" Actual", a);
|
|
443
|
+
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18);
|
|
444
|
+
emit log_named_decimal_uint(" % Delta", percentDelta, 18);
|
|
445
|
+
fail();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function assertApproxEqRel(
|
|
450
|
+
int256 a,
|
|
451
|
+
int256 b,
|
|
452
|
+
uint256 maxPercentDelta,
|
|
453
|
+
string memory err
|
|
454
|
+
) internal virtual {
|
|
455
|
+
if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.
|
|
456
|
+
|
|
457
|
+
uint256 percentDelta = stdMath.percentDelta(a, b);
|
|
458
|
+
|
|
459
|
+
if (percentDelta > maxPercentDelta) {
|
|
460
|
+
emit log_named_string ("Error", err);
|
|
461
|
+
assertApproxEqRel(a, b, maxPercentDelta);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/*//////////////////////////////////////////////////////////////
|
|
466
|
+
JSON PARSING
|
|
467
|
+
//////////////////////////////////////////////////////////////*/
|
|
468
|
+
|
|
469
|
+
// Data structures to parse Transaction objects from the broadcast artifact
|
|
470
|
+
// that conform to EIP1559. The Raw structs is what is parsed from the JSON
|
|
471
|
+
// and then converted to the one that is used by the user for better UX.
|
|
472
|
+
|
|
473
|
+
struct RawTx1559 {
|
|
474
|
+
string[] arguments;
|
|
475
|
+
address contractAddress;
|
|
476
|
+
string contractName;
|
|
477
|
+
// json value name = function
|
|
478
|
+
string functionSig;
|
|
479
|
+
bytes32 hash;
|
|
480
|
+
// json value name = tx
|
|
481
|
+
RawTx1559Detail txDetail;
|
|
482
|
+
// json value name = type
|
|
483
|
+
string opcode;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
struct RawTx1559Detail {
|
|
487
|
+
AccessList[] accessList;
|
|
488
|
+
bytes data;
|
|
489
|
+
address from;
|
|
490
|
+
bytes gas;
|
|
491
|
+
bytes nonce;
|
|
492
|
+
address to;
|
|
493
|
+
bytes txType;
|
|
494
|
+
bytes value;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
struct Tx1559 {
|
|
498
|
+
string[] arguments;
|
|
499
|
+
address contractAddress;
|
|
500
|
+
string contractName;
|
|
501
|
+
string functionSig;
|
|
502
|
+
bytes32 hash;
|
|
503
|
+
Tx1559Detail txDetail;
|
|
504
|
+
string opcode;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
struct Tx1559Detail {
|
|
508
|
+
AccessList[] accessList;
|
|
509
|
+
bytes data;
|
|
510
|
+
address from;
|
|
511
|
+
uint256 gas;
|
|
512
|
+
uint256 nonce;
|
|
513
|
+
address to;
|
|
514
|
+
uint256 txType;
|
|
515
|
+
uint256 value;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Data structures to parse Transaction objects from the broadcast artifact
|
|
519
|
+
// that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON
|
|
520
|
+
// and then converted to the one that is used by the user for better UX.
|
|
521
|
+
|
|
522
|
+
struct TxLegacy{
|
|
523
|
+
string[] arguments;
|
|
524
|
+
address contractAddress;
|
|
525
|
+
string contractName;
|
|
526
|
+
string functionSig;
|
|
527
|
+
string hash;
|
|
528
|
+
string opcode;
|
|
529
|
+
TxDetailLegacy transaction;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
struct TxDetailLegacy{
|
|
533
|
+
AccessList[] accessList;
|
|
534
|
+
uint256 chainId;
|
|
535
|
+
bytes data;
|
|
536
|
+
address from;
|
|
537
|
+
uint256 gas;
|
|
538
|
+
uint256 gasPrice;
|
|
539
|
+
bytes32 hash;
|
|
540
|
+
uint256 nonce;
|
|
541
|
+
bytes1 opcode;
|
|
542
|
+
bytes32 r;
|
|
543
|
+
bytes32 s;
|
|
544
|
+
uint256 txType;
|
|
545
|
+
address to;
|
|
546
|
+
uint8 v;
|
|
547
|
+
uint256 value;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
struct AccessList{
|
|
551
|
+
address accessAddress;
|
|
552
|
+
bytes32[] storageKeys;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Data structures to parse Receipt objects from the broadcast artifact.
|
|
556
|
+
// The Raw structs is what is parsed from the JSON
|
|
557
|
+
// and then converted to the one that is used by the user for better UX.
|
|
558
|
+
|
|
559
|
+
struct RawReceipt {
|
|
560
|
+
bytes32 blockHash;
|
|
561
|
+
bytes blockNumber;
|
|
562
|
+
address contractAddress;
|
|
563
|
+
bytes cumulativeGasUsed;
|
|
564
|
+
bytes effectiveGasPrice;
|
|
565
|
+
address from;
|
|
566
|
+
bytes gasUsed;
|
|
567
|
+
RawReceiptLog[] logs;
|
|
568
|
+
bytes logsBloom;
|
|
569
|
+
bytes status;
|
|
570
|
+
address to;
|
|
571
|
+
bytes32 transactionHash;
|
|
572
|
+
bytes transactionIndex;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
struct Receipt {
|
|
576
|
+
bytes32 blockHash;
|
|
577
|
+
uint256 blockNumber;
|
|
578
|
+
address contractAddress;
|
|
579
|
+
uint256 cumulativeGasUsed;
|
|
580
|
+
uint256 effectiveGasPrice;
|
|
581
|
+
address from;
|
|
582
|
+
uint256 gasUsed;
|
|
583
|
+
ReceiptLog[] logs;
|
|
584
|
+
bytes logsBloom;
|
|
585
|
+
uint256 status;
|
|
586
|
+
address to;
|
|
587
|
+
bytes32 transactionHash;
|
|
588
|
+
uint256 transactionIndex;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Data structures to parse the entire broadcast artifact, assuming the
|
|
592
|
+
// transactions conform to EIP1559.
|
|
593
|
+
|
|
594
|
+
struct EIP1559ScriptArtifact {
|
|
595
|
+
string[] libraries;
|
|
596
|
+
string path;
|
|
597
|
+
string[] pending;
|
|
598
|
+
Receipt[] receipts;
|
|
599
|
+
uint256 timestamp;
|
|
600
|
+
Tx1559[] transactions;
|
|
601
|
+
TxReturn[] txReturns;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
struct RawEIP1559ScriptArtifact {
|
|
605
|
+
string[] libraries;
|
|
606
|
+
string path;
|
|
607
|
+
string[] pending;
|
|
608
|
+
RawReceipt[] receipts;
|
|
609
|
+
TxReturn[] txReturns;
|
|
610
|
+
uint256 timestamp;
|
|
611
|
+
RawTx1559[] transactions;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
struct RawReceiptLog {
|
|
615
|
+
// json value = address
|
|
616
|
+
address logAddress;
|
|
617
|
+
bytes32 blockHash;
|
|
618
|
+
bytes blockNumber;
|
|
619
|
+
bytes data;
|
|
620
|
+
bytes logIndex;
|
|
621
|
+
bool removed;
|
|
622
|
+
bytes32[] topics;
|
|
623
|
+
bytes32 transactionHash;
|
|
624
|
+
bytes transactionIndex;
|
|
625
|
+
bytes transactionLogIndex;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
struct ReceiptLog {
|
|
629
|
+
// json value = address
|
|
630
|
+
address logAddress;
|
|
631
|
+
bytes32 blockHash;
|
|
632
|
+
uint256 blockNumber;
|
|
633
|
+
bytes data;
|
|
634
|
+
uint256 logIndex;
|
|
635
|
+
bytes32[] topics;
|
|
636
|
+
uint256 transactionIndex;
|
|
637
|
+
uint256 transactionLogIndex;
|
|
638
|
+
bool removed;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
struct TxReturn {
|
|
642
|
+
string internalType;
|
|
643
|
+
string value;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
function readEIP1559ScriptArtifact(string memory path)
|
|
648
|
+
internal
|
|
649
|
+
returns(EIP1559ScriptArtifact memory)
|
|
650
|
+
{
|
|
651
|
+
string memory data = vm.readFile(path);
|
|
652
|
+
bytes memory parsedData = vm.parseJson(data);
|
|
653
|
+
RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact));
|
|
654
|
+
EIP1559ScriptArtifact memory artifact;
|
|
655
|
+
artifact.libraries = rawArtifact.libraries;
|
|
656
|
+
artifact.path = rawArtifact.path;
|
|
657
|
+
artifact.timestamp = rawArtifact.timestamp;
|
|
658
|
+
artifact.pending = rawArtifact.pending;
|
|
659
|
+
artifact.txReturns = rawArtifact.txReturns;
|
|
660
|
+
artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts);
|
|
661
|
+
artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions);
|
|
662
|
+
return artifact;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs)
|
|
666
|
+
internal pure
|
|
667
|
+
returns (Tx1559[] memory)
|
|
668
|
+
{
|
|
669
|
+
Tx1559[] memory txs = new Tx1559[](rawTxs.length);
|
|
670
|
+
for (uint i; i < rawTxs.length; i++) {
|
|
671
|
+
txs[i] = rawToConvertedEIPTx1559(rawTxs[i]);
|
|
672
|
+
}
|
|
673
|
+
return txs;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function rawToConvertedEIPTx1559(RawTx1559 memory rawTx)
|
|
677
|
+
internal pure
|
|
678
|
+
returns (Tx1559 memory)
|
|
679
|
+
{
|
|
680
|
+
Tx1559 memory transaction;
|
|
681
|
+
transaction.arguments = rawTx.arguments;
|
|
682
|
+
transaction.contractName = rawTx.contractName;
|
|
683
|
+
transaction.functionSig = rawTx.functionSig;
|
|
684
|
+
transaction.hash= rawTx.hash;
|
|
685
|
+
transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail);
|
|
686
|
+
transaction.opcode= rawTx.opcode;
|
|
687
|
+
return transaction;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail)
|
|
691
|
+
internal pure
|
|
692
|
+
returns (Tx1559Detail memory)
|
|
693
|
+
{
|
|
694
|
+
Tx1559Detail memory txDetail;
|
|
695
|
+
txDetail.data = rawDetail.data;
|
|
696
|
+
txDetail.from = rawDetail.from;
|
|
697
|
+
txDetail.to = rawDetail.to;
|
|
698
|
+
txDetail.nonce = bytesToUint(rawDetail.nonce);
|
|
699
|
+
txDetail.txType = bytesToUint(rawDetail.txType);
|
|
700
|
+
txDetail.value = bytesToUint(rawDetail.value);
|
|
701
|
+
txDetail.gas = bytesToUint(rawDetail.gas);
|
|
702
|
+
txDetail.accessList = rawDetail.accessList;
|
|
703
|
+
return txDetail;
|
|
704
|
+
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function readTx1559s(string memory path)
|
|
708
|
+
internal
|
|
709
|
+
returns (Tx1559[] memory)
|
|
710
|
+
{
|
|
711
|
+
string memory deployData = vm.readFile(path);
|
|
712
|
+
bytes memory parsedDeployData =
|
|
713
|
+
vm.parseJson(deployData, ".transactions");
|
|
714
|
+
RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[]));
|
|
715
|
+
return rawToConvertedEIPTx1559s(rawTxs);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
function readTx1559(string memory path, uint256 index)
|
|
720
|
+
internal
|
|
721
|
+
returns (Tx1559 memory)
|
|
722
|
+
{
|
|
723
|
+
string memory deployData = vm.readFile(path);
|
|
724
|
+
string memory key = string(abi.encodePacked(".transactions[",vm.toString(index), "]"));
|
|
725
|
+
bytes memory parsedDeployData =
|
|
726
|
+
vm.parseJson(deployData, key);
|
|
727
|
+
RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559));
|
|
728
|
+
return rawToConvertedEIPTx1559(rawTx);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
// Analogous to readTransactions, but for receipts.
|
|
733
|
+
function readReceipts(string memory path)
|
|
734
|
+
internal
|
|
735
|
+
returns (Receipt[] memory)
|
|
736
|
+
{
|
|
737
|
+
string memory deployData = vm.readFile(path);
|
|
738
|
+
bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts");
|
|
739
|
+
RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[]));
|
|
740
|
+
return rawToConvertedReceipts(rawReceipts);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function readReceipt(string memory path, uint index)
|
|
744
|
+
internal
|
|
745
|
+
returns (Receipt memory)
|
|
746
|
+
{
|
|
747
|
+
string memory deployData = vm.readFile(path);
|
|
748
|
+
string memory key = string(abi.encodePacked(".receipts[",vm.toString(index), "]"));
|
|
749
|
+
bytes memory parsedDeployData = vm.parseJson(deployData, key);
|
|
750
|
+
RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt));
|
|
751
|
+
return rawToConvertedReceipt(rawReceipt);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function rawToConvertedReceipts(RawReceipt[] memory rawReceipts)
|
|
755
|
+
internal pure
|
|
756
|
+
returns(Receipt[] memory)
|
|
757
|
+
{
|
|
758
|
+
Receipt[] memory receipts = new Receipt[](rawReceipts.length);
|
|
759
|
+
for (uint i; i < rawReceipts.length; i++) {
|
|
760
|
+
receipts[i] = rawToConvertedReceipt(rawReceipts[i]);
|
|
761
|
+
}
|
|
762
|
+
return receipts;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function rawToConvertedReceipt(RawReceipt memory rawReceipt)
|
|
766
|
+
internal pure
|
|
767
|
+
returns(Receipt memory)
|
|
768
|
+
{
|
|
769
|
+
Receipt memory receipt;
|
|
770
|
+
receipt.blockHash = rawReceipt.blockHash;
|
|
771
|
+
receipt.to = rawReceipt.to;
|
|
772
|
+
receipt.from = rawReceipt.from;
|
|
773
|
+
receipt.contractAddress = rawReceipt.contractAddress;
|
|
774
|
+
receipt.effectiveGasPrice = bytesToUint(rawReceipt.effectiveGasPrice);
|
|
775
|
+
receipt.cumulativeGasUsed= bytesToUint(rawReceipt.cumulativeGasUsed);
|
|
776
|
+
receipt.gasUsed = bytesToUint(rawReceipt.gasUsed);
|
|
777
|
+
receipt.status = bytesToUint(rawReceipt.status);
|
|
778
|
+
receipt.transactionIndex = bytesToUint(rawReceipt.transactionIndex);
|
|
779
|
+
receipt.blockNumber = bytesToUint(rawReceipt.blockNumber);
|
|
780
|
+
receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs);
|
|
781
|
+
receipt.logsBloom = rawReceipt.logsBloom;
|
|
782
|
+
receipt.transactionHash = rawReceipt.transactionHash;
|
|
783
|
+
return receipt;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs)
|
|
787
|
+
internal pure
|
|
788
|
+
returns (ReceiptLog[] memory)
|
|
789
|
+
{
|
|
790
|
+
ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length);
|
|
791
|
+
for (uint i; i < rawLogs.length; i++) {
|
|
792
|
+
logs[i].logAddress = rawLogs[i].logAddress;
|
|
793
|
+
logs[i].blockHash = rawLogs[i].blockHash;
|
|
794
|
+
logs[i].blockNumber = bytesToUint(rawLogs[i].blockNumber);
|
|
795
|
+
logs[i].data = rawLogs[i].data;
|
|
796
|
+
logs[i].logIndex = bytesToUint(rawLogs[i].logIndex);
|
|
797
|
+
logs[i].topics = rawLogs[i].topics;
|
|
798
|
+
logs[i].transactionIndex = bytesToUint(rawLogs[i].transactionIndex);
|
|
799
|
+
logs[i].transactionLogIndex = bytesToUint(rawLogs[i].transactionLogIndex);
|
|
800
|
+
logs[i].removed = rawLogs[i].removed;
|
|
801
|
+
}
|
|
802
|
+
return logs;
|
|
803
|
+
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function bytesToUint(bytes memory b) internal pure returns (uint256){
|
|
807
|
+
uint256 number;
|
|
808
|
+
for (uint i=0; i < b.length; i++) {
|
|
809
|
+
number = number + uint(uint8(b[i]))*(2**(8*(b.length-(i+1))));
|
|
810
|
+
}
|
|
811
|
+
return number;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/*//////////////////////////////////////////////////////////////////////////
|
|
817
|
+
STD-ERRORS
|
|
818
|
+
//////////////////////////////////////////////////////////////////////////*/
|
|
819
|
+
|
|
820
|
+
library stdError {
|
|
821
|
+
bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01);
|
|
822
|
+
bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11);
|
|
823
|
+
bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12);
|
|
824
|
+
bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21);
|
|
825
|
+
bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22);
|
|
826
|
+
bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31);
|
|
827
|
+
bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32);
|
|
828
|
+
bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41);
|
|
829
|
+
bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51);
|
|
830
|
+
// DEPRECATED: Use Vm's `expectRevert` without any arguments instead
|
|
831
|
+
bytes public constant lowLevelError = bytes(""); // `0x`
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/*//////////////////////////////////////////////////////////////////////////
|
|
835
|
+
STD-STORAGE
|
|
836
|
+
//////////////////////////////////////////////////////////////////////////*/
|
|
837
|
+
|
|
838
|
+
struct StdStorage {
|
|
839
|
+
mapping (address => mapping(bytes4 => mapping(bytes32 => uint256))) slots;
|
|
840
|
+
mapping (address => mapping(bytes4 => mapping(bytes32 => bool))) finds;
|
|
841
|
+
|
|
842
|
+
bytes32[] _keys;
|
|
843
|
+
bytes4 _sig;
|
|
844
|
+
uint256 _depth;
|
|
845
|
+
address _target;
|
|
846
|
+
bytes32 _set;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
library stdStorage {
|
|
850
|
+
event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint slot);
|
|
851
|
+
event WARNING_UninitedSlot(address who, uint slot);
|
|
852
|
+
|
|
853
|
+
uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
|
|
854
|
+
int256 private constant INT256_MAX = 57896044618658097711785492504343953926634992332820282019728792003956564819967;
|
|
855
|
+
|
|
856
|
+
Vm private constant vm_std_store = Vm(address(uint160(uint256(keccak256('hevm cheat code')))));
|
|
857
|
+
|
|
858
|
+
function sigs(
|
|
859
|
+
string memory sigStr
|
|
860
|
+
)
|
|
861
|
+
internal
|
|
862
|
+
pure
|
|
863
|
+
returns (bytes4)
|
|
864
|
+
{
|
|
865
|
+
return bytes4(keccak256(bytes(sigStr)));
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against
|
|
869
|
+
// slot complexity:
|
|
870
|
+
// if flat, will be bytes32(uint256(uint));
|
|
871
|
+
// if map, will be keccak256(abi.encode(key, uint(slot)));
|
|
872
|
+
// if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))));
|
|
873
|
+
// if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth);
|
|
874
|
+
function find(
|
|
875
|
+
StdStorage storage self
|
|
876
|
+
)
|
|
877
|
+
internal
|
|
878
|
+
returns (uint256)
|
|
879
|
+
{
|
|
880
|
+
address who = self._target;
|
|
881
|
+
bytes4 fsig = self._sig;
|
|
882
|
+
uint256 field_depth = self._depth;
|
|
883
|
+
bytes32[] memory ins = self._keys;
|
|
884
|
+
|
|
885
|
+
// calldata to test against
|
|
886
|
+
if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
|
|
887
|
+
return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
|
|
888
|
+
}
|
|
889
|
+
bytes memory cald = abi.encodePacked(fsig, flatten(ins));
|
|
890
|
+
vm_std_store.record();
|
|
891
|
+
bytes32 fdat;
|
|
892
|
+
{
|
|
893
|
+
(, bytes memory rdat) = who.staticcall(cald);
|
|
894
|
+
fdat = bytesToBytes32(rdat, 32*field_depth);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
(bytes32[] memory reads, ) = vm_std_store.accesses(address(who));
|
|
898
|
+
if (reads.length == 1) {
|
|
899
|
+
bytes32 curr = vm_std_store.load(who, reads[0]);
|
|
900
|
+
if (curr == bytes32(0)) {
|
|
901
|
+
emit WARNING_UninitedSlot(who, uint256(reads[0]));
|
|
902
|
+
}
|
|
903
|
+
if (fdat != curr) {
|
|
904
|
+
require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported.");
|
|
905
|
+
}
|
|
906
|
+
emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0]));
|
|
907
|
+
self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]);
|
|
908
|
+
self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
|
|
909
|
+
} else if (reads.length > 1) {
|
|
910
|
+
for (uint256 i = 0; i < reads.length; i++) {
|
|
911
|
+
bytes32 prev = vm_std_store.load(who, reads[i]);
|
|
912
|
+
if (prev == bytes32(0)) {
|
|
913
|
+
emit WARNING_UninitedSlot(who, uint256(reads[i]));
|
|
914
|
+
}
|
|
915
|
+
// store
|
|
916
|
+
vm_std_store.store(who, reads[i], bytes32(hex"1337"));
|
|
917
|
+
bool success;
|
|
918
|
+
bytes memory rdat;
|
|
919
|
+
{
|
|
920
|
+
(success, rdat) = who.staticcall(cald);
|
|
921
|
+
fdat = bytesToBytes32(rdat, 32*field_depth);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
if (success && fdat == bytes32(hex"1337")) {
|
|
925
|
+
// we found which of the slots is the actual one
|
|
926
|
+
emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i]));
|
|
927
|
+
self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]);
|
|
928
|
+
self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
|
|
929
|
+
vm_std_store.store(who, reads[i], prev);
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
vm_std_store.store(who, reads[i], prev);
|
|
933
|
+
}
|
|
934
|
+
} else {
|
|
935
|
+
require(false, "stdStorage find(StdStorage): No storage use detected for target.");
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
require(self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], "stdStorage find(StdStorage): Slot(s) not found.");
|
|
939
|
+
|
|
940
|
+
delete self._target;
|
|
941
|
+
delete self._sig;
|
|
942
|
+
delete self._keys;
|
|
943
|
+
delete self._depth;
|
|
944
|
+
|
|
945
|
+
return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
|
|
949
|
+
self._target = _target;
|
|
950
|
+
return self;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
|
|
954
|
+
self._sig = _sig;
|
|
955
|
+
return self;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
|
|
959
|
+
self._sig = sigs(_sig);
|
|
960
|
+
return self;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
|
|
964
|
+
self._keys.push(bytes32(uint256(uint160(who))));
|
|
965
|
+
return self;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
|
|
969
|
+
self._keys.push(bytes32(amt));
|
|
970
|
+
return self;
|
|
971
|
+
}
|
|
972
|
+
function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
|
|
973
|
+
self._keys.push(key);
|
|
974
|
+
return self;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
|
|
978
|
+
self._depth = _depth;
|
|
979
|
+
return self;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function checked_write(StdStorage storage self, address who) internal {
|
|
983
|
+
checked_write(self, bytes32(uint256(uint160(who))));
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
function checked_write(StdStorage storage self, uint256 amt) internal {
|
|
987
|
+
checked_write(self, bytes32(amt));
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
function checked_write(StdStorage storage self, bool write) internal {
|
|
991
|
+
bytes32 t;
|
|
992
|
+
/// @solidity memory-safe-assembly
|
|
993
|
+
assembly {
|
|
994
|
+
t := write
|
|
995
|
+
}
|
|
996
|
+
checked_write(self, t);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
function checked_write(
|
|
1000
|
+
StdStorage storage self,
|
|
1001
|
+
bytes32 set
|
|
1002
|
+
) internal {
|
|
1003
|
+
address who = self._target;
|
|
1004
|
+
bytes4 fsig = self._sig;
|
|
1005
|
+
uint256 field_depth = self._depth;
|
|
1006
|
+
bytes32[] memory ins = self._keys;
|
|
1007
|
+
|
|
1008
|
+
bytes memory cald = abi.encodePacked(fsig, flatten(ins));
|
|
1009
|
+
if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
|
|
1010
|
+
find(self);
|
|
1011
|
+
}
|
|
1012
|
+
bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]);
|
|
1013
|
+
|
|
1014
|
+
bytes32 fdat;
|
|
1015
|
+
{
|
|
1016
|
+
(, bytes memory rdat) = who.staticcall(cald);
|
|
1017
|
+
fdat = bytesToBytes32(rdat, 32*field_depth);
|
|
1018
|
+
}
|
|
1019
|
+
bytes32 curr = vm_std_store.load(who, slot);
|
|
1020
|
+
|
|
1021
|
+
if (fdat != curr) {
|
|
1022
|
+
require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported.");
|
|
1023
|
+
}
|
|
1024
|
+
vm_std_store.store(who, slot, set);
|
|
1025
|
+
delete self._target;
|
|
1026
|
+
delete self._sig;
|
|
1027
|
+
delete self._keys;
|
|
1028
|
+
delete self._depth;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
function read(StdStorage storage self) private returns (bytes memory) {
|
|
1032
|
+
address t = self._target;
|
|
1033
|
+
uint256 s = find(self);
|
|
1034
|
+
return abi.encode(vm_std_store.load(t, bytes32(s)));
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function read_bytes32(StdStorage storage self) internal returns (bytes32) {
|
|
1038
|
+
return abi.decode(read(self), (bytes32));
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
function read_bool(StdStorage storage self) internal returns (bool) {
|
|
1043
|
+
int256 v = read_int(self);
|
|
1044
|
+
if (v == 0) return false;
|
|
1045
|
+
if (v == 1) return true;
|
|
1046
|
+
revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
function read_address(StdStorage storage self) internal returns (address) {
|
|
1050
|
+
return abi.decode(read(self), (address));
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
function read_uint(StdStorage storage self) internal returns (uint256) {
|
|
1054
|
+
return abi.decode(read(self), (uint256));
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function read_int(StdStorage storage self) internal returns (int256) {
|
|
1058
|
+
return abi.decode(read(self), (int256));
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
function bytesToBytes32(bytes memory b, uint offset) public pure returns (bytes32) {
|
|
1062
|
+
bytes32 out;
|
|
1063
|
+
|
|
1064
|
+
uint256 max = b.length > 32 ? 32 : b.length;
|
|
1065
|
+
for (uint i = 0; i < max; i++) {
|
|
1066
|
+
out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
|
|
1067
|
+
}
|
|
1068
|
+
return out;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
function flatten(bytes32[] memory b) private pure returns (bytes memory)
|
|
1072
|
+
{
|
|
1073
|
+
bytes memory result = new bytes(b.length * 32);
|
|
1074
|
+
for (uint256 i = 0; i < b.length; i++) {
|
|
1075
|
+
bytes32 k = b[i];
|
|
1076
|
+
/// @solidity memory-safe-assembly
|
|
1077
|
+
assembly {
|
|
1078
|
+
mstore(add(result, add(32, mul(32, i))), k)
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
return result;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
/*//////////////////////////////////////////////////////////////////////////
|
|
1091
|
+
STD-MATH
|
|
1092
|
+
//////////////////////////////////////////////////////////////////////////*/
|
|
1093
|
+
|
|
1094
|
+
library stdMath {
|
|
1095
|
+
int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;
|
|
1096
|
+
|
|
1097
|
+
function abs(int256 a) internal pure returns (uint256) {
|
|
1098
|
+
// Required or it will fail when `a = type(int256).min`
|
|
1099
|
+
if (a == INT256_MIN)
|
|
1100
|
+
return 57896044618658097711785492504343953926634992332820282019728792003956564819968;
|
|
1101
|
+
|
|
1102
|
+
return uint256(a > 0 ? a : -a);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
function delta(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
1106
|
+
return a > b
|
|
1107
|
+
? a - b
|
|
1108
|
+
: b - a;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
function delta(int256 a, int256 b) internal pure returns (uint256) {
|
|
1112
|
+
// a and b are of the same sign
|
|
1113
|
+
// this works thanks to two's complement, the left-most bit is the sign bit
|
|
1114
|
+
if ((a ^ b) > -1) {
|
|
1115
|
+
return delta(abs(a), abs(b));
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// a and b are of opposite signs
|
|
1119
|
+
return abs(a) + abs(b);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {
|
|
1123
|
+
uint256 absDelta = delta(a, b);
|
|
1124
|
+
|
|
1125
|
+
return absDelta * 1e18 / b;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
function percentDelta(int256 a, int256 b) internal pure returns (uint256) {
|
|
1129
|
+
uint256 absDelta = delta(a, b);
|
|
1130
|
+
uint256 absB = abs(b);
|
|
1131
|
+
|
|
1132
|
+
return absDelta * 1e18 / absB;
|
|
1133
|
+
}
|
|
1134
|
+
}
|