poseidon-solidity-example/lib/forge-std/README.md
lib/forge-std/README.mdRaw
1# Forge Standard Library • [](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml)
2
3Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes.
4
5**Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).**
6
7## Install
8
9```bash
10forge install foundry-rs/forge-std
11```
12
13## Contracts
14### stdError
15
16This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors.
17
18See the contract itself for all error codes.
19
20#### Example usage
21
22```solidity
23
24import "forge-std/Test.sol";
25
26contract TestContract is Test {
27 ErrorsTest test;
28
29 function setUp() public {
30 test = new ErrorsTest();
31 }
32
33 function testExpectArithmetic() public {
34 vm.expectRevert(stdError.arithmeticError);
35 test.arithmeticError(10);
36 }
37}
38
39contract ErrorsTest {
40 function arithmeticError(uint256 a) public {
41 uint256 a = a - 100;
42 }
43}
44```
45
46### stdStorage
47
48This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`).
49
50This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth.
51
52I.e.:
53```solidity
54struct T {
55 // depth 0
56 uint256 a;
57 // depth 1
58 uint256 b;
59}
60```
61
62#### Example usage
63
64```solidity
65import "forge-std/Test.sol";
66
67contract TestContract is Test {
68 using stdStorage for StdStorage;
69
70 Storage test;
71
72 function setUp() public {
73 test = new Storage();
74 }
75
76 function testFindExists() public {
77 // Lets say we want to find the slot for the public
78 // variable `exists`. We just pass in the function selector
79 // to the `find` command
80 uint256 slot = stdstore.target(address(test)).sig("exists()").find();
81 assertEq(slot, 0);
82 }
83
84 function testWriteExists() public {
85 // Lets say we want to write to the slot for the public
86 // variable `exists`. We just pass in the function selector
87 // to the `checked_write` command
88 stdstore.target(address(test)).sig("exists()").checked_write(100);
89 assertEq(test.exists(), 100);
90 }
91
92 // It supports arbitrary storage layouts, like assembly based storage locations
93 function testFindHidden() public {
94 // `hidden` is a random hash of a bytes, iteration through slots would
95 // not find it. Our mechanism does
96 // Also, you can use the selector instead of a string
97 uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find();
98 assertEq(slot, uint256(keccak256("my.random.var")));
99 }
100
101 // If targeting a mapping, you have to pass in the keys necessary to perform the find
102 // i.e.:
103 function testFindMapping() public {
104 uint256 slot = stdstore
105 .target(address(test))
106 .sig(test.map_addr.selector)
107 .with_key(address(this))
108 .find();
109 // in the `Storage` constructor, we wrote that this address' value was 1 in the map
110 // so when we load the slot, we expect it to be 1
111 assertEq(uint(vm.load(address(test), bytes32(slot))), 1);
112 }
113
114 // If the target is a struct, you can specify the field depth:
115 function testFindStruct() public {
116 // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc.
117 uint256 slot_for_a_field = stdstore
118 .target(address(test))
119 .sig(test.basicStruct.selector)
120 .depth(0)
121 .find();
122
123 uint256 slot_for_b_field = stdstore
124 .target(address(test))
125 .sig(test.basicStruct.selector)
126 .depth(1)
127 .find();
128
129 assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1);
130 assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2);
131 }
132}
133
134// A complex storage contract
135contract Storage {
136 struct UnpackedStruct {
137 uint256 a;
138 uint256 b;
139 }
140
141 constructor() {
142 map_addr[msg.sender] = 1;
143 }
144
145 uint256 public exists = 1;
146 mapping(address => uint256) public map_addr;
147 // mapping(address => Packed) public map_packed;
148 mapping(address => UnpackedStruct) public map_struct;
149 mapping(address => mapping(address => uint256)) public deep_map;
150 mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct;
151 UnpackedStruct public basicStruct = UnpackedStruct({
152 a: 1,
153 b: 2
154 });
155
156 function hidden() public view returns (bytes32 t) {
157 // an extremely hidden storage slot
158 bytes32 slot = keccak256("my.random.var");
159 assembly {
160 t := sload(slot)
161 }
162 }
163}
164```
165
166### stdCheats
167
168This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you.
169
170
171#### Example usage:
172```solidity
173
174// SPDX-License-Identifier: MIT
175pragma solidity ^0.8.0;
176
177import "forge-std/Test.sol";
178
179// Inherit the stdCheats
180contract StdCheatsTest is Test {
181 Bar test;
182 function setUp() public {
183 test = new Bar();
184 }
185
186 function testHoax() public {
187 // we call `hoax`, which gives the target address
188 // eth and then calls `prank`
189 hoax(address(1337));
190 test.bar{value: 100}(address(1337));
191
192 // overloaded to allow you to specify how much eth to
193 // initialize the address with
194 hoax(address(1337), 1);
195 test.bar{value: 1}(address(1337));
196 }
197
198 function testStartHoax() public {
199 // we call `startHoax`, which gives the target address
200 // eth and then calls `startPrank`
201 //
202 // it is also overloaded so that you can specify an eth amount
203 startHoax(address(1337));
204 test.bar{value: 100}(address(1337));
205 test.bar{value: 100}(address(1337));
206 vm.stopPrank();
207 test.bar(address(this));
208 }
209}
210
211contract Bar {
212 function bar(address expectedSender) public payable {
213 require(msg.sender == expectedSender, "!prank");
214 }
215}
216```
217
218### Std Assertions
219
220Expand upon the assertion functions from the `DSTest` library.
221
222### `console.log`
223
224Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log).
225It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces.
226
227```solidity
228// import it indirectly via Test.sol
229import "forge-std/Test.sol";
230// or directly import it
231import "forge-std/console2.sol";
232...
233console2.log(someValue);
234```
235
236If you need compatibility with Hardhat, you must use the standard `console.sol` instead.
237Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces.
238
239```solidity
240// import it indirectly via Test.sol
241import "forge-std/Test.sol";
242// or directly import it
243import "forge-std/console.sol";
244...
245console.log(someValue);
246```
247
248## License
249
250Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license.