poseidon-solidity-example/lib/forge-std/src/StdCheats.sol
lib/forge-std/src/StdCheats.solRaw
1// SPDX-License-Identifier: MIT
2pragma solidity >=0.6.2 <0.9.0;
3
4pragma experimental ABIEncoderV2;
5
6import {StdStorage, stdStorage} from "./StdStorage.sol";
7import {Vm} from "./Vm.sol";
8
9abstract contract StdCheatsSafe {
10 Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
11
12 bool private gasMeteringOff;
13
14 // Data structures to parse Transaction objects from the broadcast artifact
15 // that conform to EIP1559. The Raw structs is what is parsed from the JSON
16 // and then converted to the one that is used by the user for better UX.
17
18 struct RawTx1559 {
19 string[] arguments;
20 address contractAddress;
21 string contractName;
22 // json value name = function
23 string functionSig;
24 bytes32 hash;
25 // json value name = tx
26 RawTx1559Detail txDetail;
27 // json value name = type
28 string opcode;
29 }
30
31 struct RawTx1559Detail {
32 AccessList[] accessList;
33 bytes data;
34 address from;
35 bytes gas;
36 bytes nonce;
37 address to;
38 bytes txType;
39 bytes value;
40 }
41
42 struct Tx1559 {
43 string[] arguments;
44 address contractAddress;
45 string contractName;
46 string functionSig;
47 bytes32 hash;
48 Tx1559Detail txDetail;
49 string opcode;
50 }
51
52 struct Tx1559Detail {
53 AccessList[] accessList;
54 bytes data;
55 address from;
56 uint256 gas;
57 uint256 nonce;
58 address to;
59 uint256 txType;
60 uint256 value;
61 }
62
63 // Data structures to parse Transaction objects from the broadcast artifact
64 // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON
65 // and then converted to the one that is used by the user for better UX.
66
67 struct TxLegacy {
68 string[] arguments;
69 address contractAddress;
70 string contractName;
71 string functionSig;
72 string hash;
73 string opcode;
74 TxDetailLegacy transaction;
75 }
76
77 struct TxDetailLegacy {
78 AccessList[] accessList;
79 uint256 chainId;
80 bytes data;
81 address from;
82 uint256 gas;
83 uint256 gasPrice;
84 bytes32 hash;
85 uint256 nonce;
86 bytes1 opcode;
87 bytes32 r;
88 bytes32 s;
89 uint256 txType;
90 address to;
91 uint8 v;
92 uint256 value;
93 }
94
95 struct AccessList {
96 address accessAddress;
97 bytes32[] storageKeys;
98 }
99
100 // Data structures to parse Receipt objects from the broadcast artifact.
101 // The Raw structs is what is parsed from the JSON
102 // and then converted to the one that is used by the user for better UX.
103
104 struct RawReceipt {
105 bytes32 blockHash;
106 bytes blockNumber;
107 address contractAddress;
108 bytes cumulativeGasUsed;
109 bytes effectiveGasPrice;
110 address from;
111 bytes gasUsed;
112 RawReceiptLog[] logs;
113 bytes logsBloom;
114 bytes status;
115 address to;
116 bytes32 transactionHash;
117 bytes transactionIndex;
118 }
119
120 struct Receipt {
121 bytes32 blockHash;
122 uint256 blockNumber;
123 address contractAddress;
124 uint256 cumulativeGasUsed;
125 uint256 effectiveGasPrice;
126 address from;
127 uint256 gasUsed;
128 ReceiptLog[] logs;
129 bytes logsBloom;
130 uint256 status;
131 address to;
132 bytes32 transactionHash;
133 uint256 transactionIndex;
134 }
135
136 // Data structures to parse the entire broadcast artifact, assuming the
137 // transactions conform to EIP1559.
138
139 struct EIP1559ScriptArtifact {
140 string[] libraries;
141 string path;
142 string[] pending;
143 Receipt[] receipts;
144 uint256 timestamp;
145 Tx1559[] transactions;
146 TxReturn[] txReturns;
147 }
148
149 struct RawEIP1559ScriptArtifact {
150 string[] libraries;
151 string path;
152 string[] pending;
153 RawReceipt[] receipts;
154 TxReturn[] txReturns;
155 uint256 timestamp;
156 RawTx1559[] transactions;
157 }
158
159 struct RawReceiptLog {
160 // json value = address
161 address logAddress;
162 bytes32 blockHash;
163 bytes blockNumber;
164 bytes data;
165 bytes logIndex;
166 bool removed;
167 bytes32[] topics;
168 bytes32 transactionHash;
169 bytes transactionIndex;
170 bytes transactionLogIndex;
171 }
172
173 struct ReceiptLog {
174 // json value = address
175 address logAddress;
176 bytes32 blockHash;
177 uint256 blockNumber;
178 bytes data;
179 uint256 logIndex;
180 bytes32[] topics;
181 uint256 transactionIndex;
182 uint256 transactionLogIndex;
183 bool removed;
184 }
185
186 struct TxReturn {
187 string internalType;
188 string value;
189 }
190
191 function assumeNoPrecompiles(address addr) internal virtual {
192 // Assembly required since `block.chainid` was introduced in 0.8.0.
193 uint256 chainId;
194 assembly {
195 chainId := chainid()
196 }
197 assumeNoPrecompiles(addr, chainId);
198 }
199
200 function assumeNoPrecompiles(address addr, uint256 chainId) internal pure virtual {
201 // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific
202 // address), but the same rationale for excluding them applies so we include those too.
203
204 // These should be present on all EVM-compatible chains.
205 vm.assume(addr < address(0x1) || addr > address(0x9));
206
207 // forgefmt: disable-start
208 if (chainId == 10 || chainId == 420) {
209 // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21
210 vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800));
211 } else if (chainId == 42161 || chainId == 421613) {
212 // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains
213 vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068));
214 } else if (chainId == 43114 || chainId == 43113) {
215 // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59
216 vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff));
217 vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF));
218 vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff));
219 }
220 // forgefmt: disable-end
221 }
222
223 function readEIP1559ScriptArtifact(string memory path)
224 internal
225 view
226 virtual
227 returns (EIP1559ScriptArtifact memory)
228 {
229 string memory data = vm.readFile(path);
230 bytes memory parsedData = vm.parseJson(data);
231 RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact));
232 EIP1559ScriptArtifact memory artifact;
233 artifact.libraries = rawArtifact.libraries;
234 artifact.path = rawArtifact.path;
235 artifact.timestamp = rawArtifact.timestamp;
236 artifact.pending = rawArtifact.pending;
237 artifact.txReturns = rawArtifact.txReturns;
238 artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts);
239 artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions);
240 return artifact;
241 }
242
243 function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) {
244 Tx1559[] memory txs = new Tx1559[](rawTxs.length);
245 for (uint256 i; i < rawTxs.length; i++) {
246 txs[i] = rawToConvertedEIPTx1559(rawTxs[i]);
247 }
248 return txs;
249 }
250
251 function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) {
252 Tx1559 memory transaction;
253 transaction.arguments = rawTx.arguments;
254 transaction.contractName = rawTx.contractName;
255 transaction.functionSig = rawTx.functionSig;
256 transaction.hash = rawTx.hash;
257 transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail);
258 transaction.opcode = rawTx.opcode;
259 return transaction;
260 }
261
262 function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail)
263 internal
264 pure
265 virtual
266 returns (Tx1559Detail memory)
267 {
268 Tx1559Detail memory txDetail;
269 txDetail.data = rawDetail.data;
270 txDetail.from = rawDetail.from;
271 txDetail.to = rawDetail.to;
272 txDetail.nonce = _bytesToUint(rawDetail.nonce);
273 txDetail.txType = _bytesToUint(rawDetail.txType);
274 txDetail.value = _bytesToUint(rawDetail.value);
275 txDetail.gas = _bytesToUint(rawDetail.gas);
276 txDetail.accessList = rawDetail.accessList;
277 return txDetail;
278 }
279
280 function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) {
281 string memory deployData = vm.readFile(path);
282 bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions");
283 RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[]));
284 return rawToConvertedEIPTx1559s(rawTxs);
285 }
286
287 function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) {
288 string memory deployData = vm.readFile(path);
289 string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]"));
290 bytes memory parsedDeployData = vm.parseJson(deployData, key);
291 RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559));
292 return rawToConvertedEIPTx1559(rawTx);
293 }
294
295 // Analogous to readTransactions, but for receipts.
296 function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) {
297 string memory deployData = vm.readFile(path);
298 bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts");
299 RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[]));
300 return rawToConvertedReceipts(rawReceipts);
301 }
302
303 function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) {
304 string memory deployData = vm.readFile(path);
305 string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]"));
306 bytes memory parsedDeployData = vm.parseJson(deployData, key);
307 RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt));
308 return rawToConvertedReceipt(rawReceipt);
309 }
310
311 function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) {
312 Receipt[] memory receipts = new Receipt[](rawReceipts.length);
313 for (uint256 i; i < rawReceipts.length; i++) {
314 receipts[i] = rawToConvertedReceipt(rawReceipts[i]);
315 }
316 return receipts;
317 }
318
319 function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) {
320 Receipt memory receipt;
321 receipt.blockHash = rawReceipt.blockHash;
322 receipt.to = rawReceipt.to;
323 receipt.from = rawReceipt.from;
324 receipt.contractAddress = rawReceipt.contractAddress;
325 receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice);
326 receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed);
327 receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed);
328 receipt.status = _bytesToUint(rawReceipt.status);
329 receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex);
330 receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber);
331 receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs);
332 receipt.logsBloom = rawReceipt.logsBloom;
333 receipt.transactionHash = rawReceipt.transactionHash;
334 return receipt;
335 }
336
337 function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs)
338 internal
339 pure
340 virtual
341 returns (ReceiptLog[] memory)
342 {
343 ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length);
344 for (uint256 i; i < rawLogs.length; i++) {
345 logs[i].logAddress = rawLogs[i].logAddress;
346 logs[i].blockHash = rawLogs[i].blockHash;
347 logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber);
348 logs[i].data = rawLogs[i].data;
349 logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex);
350 logs[i].topics = rawLogs[i].topics;
351 logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex);
352 logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex);
353 logs[i].removed = rawLogs[i].removed;
354 }
355 return logs;
356 }
357
358 // Deploy a contract by fetching the contract bytecode from
359 // the artifacts directory
360 // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))`
361 function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) {
362 bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
363 /// @solidity memory-safe-assembly
364 assembly {
365 addr := create(0, add(bytecode, 0x20), mload(bytecode))
366 }
367
368 require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed.");
369 }
370
371 function deployCode(string memory what) internal virtual returns (address addr) {
372 bytes memory bytecode = vm.getCode(what);
373 /// @solidity memory-safe-assembly
374 assembly {
375 addr := create(0, add(bytecode, 0x20), mload(bytecode))
376 }
377
378 require(addr != address(0), "StdCheats deployCode(string): Deployment failed.");
379 }
380
381 /// @dev deploy contract with value on construction
382 function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) {
383 bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
384 /// @solidity memory-safe-assembly
385 assembly {
386 addr := create(val, add(bytecode, 0x20), mload(bytecode))
387 }
388
389 require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed.");
390 }
391
392 function deployCode(string memory what, uint256 val) internal virtual returns (address addr) {
393 bytes memory bytecode = vm.getCode(what);
394 /// @solidity memory-safe-assembly
395 assembly {
396 addr := create(val, add(bytecode, 0x20), mload(bytecode))
397 }
398
399 require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed.");
400 }
401
402 // creates a labeled address and the corresponding private key
403 function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) {
404 privateKey = uint256(keccak256(abi.encodePacked(name)));
405 addr = vm.addr(privateKey);
406 vm.label(addr, name);
407 }
408
409 // creates a labeled address
410 function makeAddr(string memory name) internal virtual returns (address addr) {
411 (addr,) = makeAddrAndKey(name);
412 }
413
414 function deriveRememberKey(string memory mnemonic, uint32 index)
415 internal
416 virtual
417 returns (address who, uint256 privateKey)
418 {
419 privateKey = vm.deriveKey(mnemonic, index);
420 who = vm.rememberKey(privateKey);
421 }
422
423 function _bytesToUint(bytes memory b) private pure returns (uint256) {
424 require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32.");
425 return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));
426 }
427
428 function isFork() internal view virtual returns (bool status) {
429 try vm.activeFork() {
430 status = true;
431 } catch (bytes memory) {}
432 }
433
434 modifier skipWhenForking() {
435 if (!isFork()) {
436 _;
437 }
438 }
439
440 modifier skipWhenNotForking() {
441 if (isFork()) {
442 _;
443 }
444 }
445
446 modifier noGasMetering() {
447 vm.pauseGasMetering();
448 // To prevent turning gas monitoring back on with nested functions that use this modifier,
449 // we check if gasMetering started in the off position. If it did, we don't want to turn
450 // it back on until we exit the top level function that used the modifier
451 //
452 // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well.
453 // funcA will have `gasStartedOff` as false, funcB will have it as true,
454 // so we only turn metering back on at the end of the funcA
455 bool gasStartedOff = gasMeteringOff;
456 gasMeteringOff = true;
457
458 _;
459
460 // if gas metering was on when this modifier was called, turn it back on at the end
461 if (!gasStartedOff) {
462 gasMeteringOff = false;
463 vm.resumeGasMetering();
464 }
465 }
466
467 // a cheat for fuzzing addresses that are payable only
468 // see https://github.com/foundry-rs/foundry/issues/3631
469 function assumePayable(address addr) internal virtual {
470 (bool success,) = payable(addr).call{value: 0}("");
471 vm.assume(success);
472 }
473}
474
475// Wrappers around cheatcodes to avoid footguns
476abstract contract StdCheats is StdCheatsSafe {
477 using stdStorage for StdStorage;
478
479 StdStorage private stdstore;
480 Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
481
482 // Skip forward or rewind time by the specified number of seconds
483 function skip(uint256 time) internal virtual {
484 vm.warp(block.timestamp + time);
485 }
486
487 function rewind(uint256 time) internal virtual {
488 vm.warp(block.timestamp - time);
489 }
490
491 // Setup a prank from an address that has some ether
492 function hoax(address who) internal virtual {
493 vm.deal(who, 1 << 128);
494 vm.prank(who);
495 }
496
497 function hoax(address who, uint256 give) internal virtual {
498 vm.deal(who, give);
499 vm.prank(who);
500 }
501
502 function hoax(address who, address origin) internal virtual {
503 vm.deal(who, 1 << 128);
504 vm.prank(who, origin);
505 }
506
507 function hoax(address who, address origin, uint256 give) internal virtual {
508 vm.deal(who, give);
509 vm.prank(who, origin);
510 }
511
512 // Start perpetual prank from an address that has some ether
513 function startHoax(address who) internal virtual {
514 vm.deal(who, 1 << 128);
515 vm.startPrank(who);
516 }
517
518 function startHoax(address who, uint256 give) internal virtual {
519 vm.deal(who, give);
520 vm.startPrank(who);
521 }
522
523 // Start perpetual prank from an address that has some ether
524 // tx.origin is set to the origin parameter
525 function startHoax(address who, address origin) internal virtual {
526 vm.deal(who, 1 << 128);
527 vm.startPrank(who, origin);
528 }
529
530 function startHoax(address who, address origin, uint256 give) internal virtual {
531 vm.deal(who, give);
532 vm.startPrank(who, origin);
533 }
534
535 function changePrank(address who) internal virtual {
536 vm.stopPrank();
537 vm.startPrank(who);
538 }
539
540 // The same as Vm's `deal`
541 // Use the alternative signature for ERC20 tokens
542 function deal(address to, uint256 give) internal virtual {
543 vm.deal(to, give);
544 }
545
546 // Set the balance of an account for any ERC20 token
547 // Use the alternative signature to update `totalSupply`
548 function deal(address token, address to, uint256 give) internal virtual {
549 deal(token, to, give, false);
550 }
551
552 function deal(address token, address to, uint256 give, bool adjust) internal virtual {
553 // get current balance
554 (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to));
555 uint256 prevBal = abi.decode(balData, (uint256));
556
557 // update balance
558 stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give);
559
560 // update total supply
561 if (adjust) {
562 (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd));
563 uint256 totSup = abi.decode(totSupData, (uint256));
564 if (give < prevBal) {
565 totSup -= (prevBal - give);
566 } else {
567 totSup += (give - prevBal);
568 }
569 stdstore.target(token).sig(0x18160ddd).checked_write(totSup);
570 }
571 }
572}