-
Notifications
You must be signed in to change notification settings - Fork 615
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cheatcodes): docs for newly added cheatcodes (#1291)
- Loading branch information
Showing
9 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
## `assumeNoRevert` | ||
|
||
### Signature | ||
|
||
```solidity | ||
function assumeNoRevert() external; | ||
``` | ||
|
||
### Description | ||
|
||
The fuzzer will discard the current fuzz inputs and start a new fuzz run if next call reverted. | ||
|
||
The test may fail if you hit the max number of rejects. | ||
|
||
You can configure the rejection thresholds by setting [`fuzz.max_test_rejects`][max-test-rejects] in your `foundry.toml` file. | ||
|
||
### Examples | ||
|
||
For a function that requires an amount in certain range: | ||
```solidity | ||
function doSomething(uint256 amount) public { | ||
require(amount > 100 ether && amount < 1_000 ether); | ||
} | ||
``` | ||
reverts are discarded, resulting in test pass (or fail if max number of rejects hit): | ||
```solidity | ||
function testSomething(uint256 amount) public { | ||
vm.assumeNoRevert(); | ||
target.doSomething(amount); | ||
// [PASS] | ||
} | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
## `copyStorage` | ||
|
||
### Signature | ||
|
||
```solidity | ||
function copyStorage(address from, address to) external; | ||
``` | ||
|
||
### Description | ||
|
||
Utility cheatcode to copy storage of `from` contract to another `to` contract. | ||
Cheatcode is not allowed if the target address has arbitrary storage set. | ||
|
||
### Examples | ||
|
||
Given a contract | ||
```solidity | ||
contract Counter { | ||
uint256 public count; | ||
function setCount(uint256 x) public { | ||
count = x; | ||
} | ||
} | ||
``` | ||
using `copyStorage` cheatcode copies the storage set on an instance to another address: | ||
```solidity | ||
function testCopyStorage() public { | ||
Counter original = new Counter(); | ||
original.setCount(1000); | ||
Counter copy = new Counter(); | ||
copy.setCount(1); | ||
// Check initial count on copy. | ||
assertEq(copy.count(), 1); | ||
vm.copyStorage(address(original), address(copy)); | ||
// Value is copied from first contract to copy. | ||
assertEq(copy.count(), 1000); | ||
} | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
## Fuzzer | ||
|
||
- [`assume`](./assume.md) | ||
- [`assumeNoRevert`](./assume-no-revert.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
## `mockFunction` | ||
|
||
### Signature | ||
|
||
```solidity | ||
function mockFunction(address callee, address target, bytes calldata data) external; | ||
``` | ||
|
||
### Description | ||
|
||
Executes calls to an address `callee` with bytecode of address `target` if the call data either strictly or loosely matches `data`. | ||
|
||
When a call is made to `callee` the call data is first checked to see if it matches in its entirety with `data`. | ||
If not, the call data is checked to see if there is a partial match on function selector. | ||
|
||
If a match is found, then call is executed using the bytecode of `target` address. | ||
|
||
> ℹ️ **Isolated tests** | ||
> | ||
> This cheatcode does not currently work if using isolated test mode. | ||
### Examples | ||
|
||
For two contracts (with same storage layout): | ||
```solidity | ||
contract Counter { | ||
uint256 public a; | ||
function count(uint256 x) public { | ||
a = 321 + x; | ||
} | ||
} | ||
contract ModelCounter { | ||
uint256 public a; | ||
function count(uint256 x) public { | ||
a = 123 + x; | ||
} | ||
} | ||
``` | ||
Mocking an exact call to `count` function: | ||
|
||
```solidity | ||
function testMockFunction() public { | ||
vm.mockFunction( | ||
address(counter), | ||
address(model), | ||
abi.encodeWithSelector(Counter.count.selector, 456) | ||
); | ||
counter.count(456); | ||
assertEq(counter.a(), 123 + 456); | ||
counter.count(567); | ||
assertEq(counter.a(), 321 + 567); | ||
} | ||
``` | ||
|
||
Mocking all calls to `count` function: | ||
|
||
```solidity | ||
function testMockCall() public { | ||
vm.mockFunction( | ||
address(counter), | ||
address(model), | ||
abi.encodeWithSelector(Counter.count.selector) | ||
); | ||
counter.count(678); | ||
assertEq(counter.a(), 123 + 678); | ||
counter.count(789); | ||
assertEq(counter.a(), 123 + 789); | ||
} | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
## `setArbitraryStorage` | ||
|
||
### Signature | ||
|
||
```solidity | ||
function setArbitraryStorage(address target) external; | ||
``` | ||
|
||
### Description | ||
|
||
Utility cheatcode to make the storage of the given address fully symbolic. | ||
Any subsequent `SLOAD` to target storage reads an arbitrary value which is memorized and returned if the same slot is loaded again. | ||
If the storage slot is explicitly written (before or after first load), then the written value is returned. | ||
|
||
### Examples | ||
|
||
For a contract with following storage layout: | ||
```solidity | ||
contract Counter { | ||
address[] public owners; | ||
function getOwner(uint256 pos) public view returns (address) { | ||
return owners[pos]; | ||
} | ||
function setOwner(uint256 pos, address owner) public { | ||
owners[pos] = owner; | ||
} | ||
} | ||
``` | ||
using `setArbitraryStorage` cheatcode ensures that arbitrary values are returned: | ||
```solidity | ||
contract ArbitraryStorageTest is Test { | ||
function testArbitraryStorage() public { | ||
Counter counter = new Counter(); | ||
vm.setArbitraryStorage(address(counter)); | ||
// Next call would fail with array out of bounds without arbitrary storage | ||
address owner = counter.getOwner(55); | ||
// Subsequent calls to same slot returns same value | ||
assertEq(counter.getOwner(55), owner); | ||
// The new value is returned if explicitly written | ||
counter.setOwner(55, address(111)); | ||
assertEq(counter.getOwner(55), address(111)); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters