Foundry Cheatsheet
A cheatsheet for commonly used commands and cheatcodes in Foundry.
A copy of this cheatsheet can be found in this gist.
Setup
Creating new projects
Create a new project:
forge init <project_name>
Create a new project using a template:
forge init --template <template> <project_name>
# Example
forge init --template https://github.com/zobront/paradigm-ctf paradigm_ctf
Usage in existing projects
Initialize Foundry:
# Create required directories
mkdir out lib
# Add `forge-std` module to `lib`
git submodule add https://github.com/foundry-rs/forge-std lib/forge-std
# Create foundry.toml
touch foundry.toml
Specify directories in foundry.toml
:
[profile.default]
src = "contracts"
out = "out"
lib = "lib"
Dependencies
Adding dependencies
Install dependencies in an existing project:
forge install
To add a new dependency:
forge install <dependency>
# Example
forge install openzeppelin/openzeppelin-contracts
To add dependencies to existing git repositories:
# Do not create a commit
forge install --no-commit <dependency>
# Do not create a git repository
forge install --no-git <dependency>
Remappings
Forge can automatically deduce remappings:
forge remappings > remappings.txt
To customize a remapping, simply add it to remappings.txt
:
echo "@openzeppelin/=lib/openzeppelin-contracts/" > remappings.txt
Testing
To run tests:
forge test
Verbosity
-vv
showsconsole.log
output.-vvv
shows execution traces for failing tests.-vvvv
shows execution traces for all tests, and setup traces for failing tests.-vvvvv
shows execution and setup traces for all tests.
To run specific tests:
--match-test
runs tests matching the specified regex.--match-contract
runs tests in contracts matching the specified regex.--match-path
runs tests in source files matching the specified path.
Fork testing
To fork a network:
forge test --fork-url <rpc_url>
To identify contracts in a forked environment, pass your Etherscan API key using --etherscan-api-key
:
forge test --fork-url <rpc_url> --etherscan-api-key <etherscan_api_key>
Cheatcodes
Refer to Cheatcodes Reference for all available cheatcodes.
Context
// Set block.timestamp
vm.warp(uint256 timestamp)
// Increase block.timestamp by specified seconds
skip(uint256 time)
// Decrease block.timestamp by specified seconds
rewind(uint256 time)
// Set block.number
vm.roll(uint256 blockNumber)
Storage and memory
// Load a storage slot from an address
vm.load(address account, bytes32 slot)
// Store a value to an address' storage slot
vm.store(address account, bytes32 slot, bytes32 value)
// Set code at address
vm.etch(address addr, bytes calldata code)
Caller
// Set msg.sender for the next call
vm.prank(address msgSender)
// Set msg.sender for subsequent calls
vm.startPrank(address msgSender)
// Reset msg.sender for subsequent calls
vm.stopPrank()
// Change msg.sender for subsequent calls
changePrank(address msgSender)
// Set msg.sender and give it ether for the next call
hoax(address who)
hoax(address who, uint256 give)
hoax(address who, address origin)
hoax(address who, address origin, uint256 give)
// Set msg.sender and give it ether for subsequent calls
startHoax(address who)
startHoax(address who, uint256 give)
startHoax(address who, address origin)
startHoax(address who, address origin, uint256 give)
Calls
// Mock calls to an address `where`. If the call data `data` matches, return `retdata`
vm.mockCall(address where, bytes calldata data, bytes calldata retdata);
// Same as the above, but msg.value also has to match `value`
vm.mockCall(address where, uint256 value, bytes calldata data, bytes calldata retdata);
Example usage:
function testMockCall() public {
// Without value
vm.mockCall(
address(token),
abi.encodeWithSelector(token.balanceOf.selector, ALICE),
abi.encode(10)
);
assertEq(token.balanceOf(ALICE), 10);
// With value
vm.mockCall(
address(market),
10 ether,
abi.encodeWithSignature("pay(address,uint256)", ALICE, 10 ether),
abi.encode(true)
);
assertTrue(market.pay{value: 10 ether}(ALICE, 10 ether));
}
Reverts
// Expect the next call to revert
vm.expectRevert()
// Expect the next call to revert with `message`
vm.expectRevert(bytes calldata message)
// Expect the next call to revert with `bytes4 data` (used for custom error selectors)
vm.expectRevert(bytes4 data)
Snapshots
// Take a snapshot of the current state
uint256 snapshot = vm.snapshot();
// Restore the state
vm.revertTo(uint256 snapshot);
Std Libraries
Refer to Forge Std’s Test
for all functionality.
Balances
// Set ether balance for an address
deal(address to, uint256 balance)
// Set ERC20 token balance for an address
deal(address token, address to, uint256 balance)
// Set ERC20 token balance for an address and increase totalSupply if `adjust` is true
deal(address token, address to, uint256 balance, bool adjust)
// Give ERC721 token with `id` to an address
dealERC721(address token, address to, uint256 id)
// Set ERC1155 token balance for an address
dealERC1155(address token, address to, uint256 id, uint256 balance)
// Set ERC1155 token balance for an address and adjust totalSupply
dealERC1155(address token, address to, uint256 id, uint256 balance, bool adjust)
Errors
From forge-std/std-errors
, used to catch internal Solidity errors:
stdError.assertionError
- anassert
fails.stdError.arithmeticError
- an arithmetic operation fails (e.g. overflow/underflow).stdError.divisionError
- a division fails (e.g. division by zero).stdError.indexOOBError
- accessing an element of an array that is out of bounds.stdError.popError
- popping from an empty array. Does not work for empty arrays in external contracts.stdError.enumConversionError
- converting a number larger than the number of enum variants to an enum.stdError.encodeStorageError
- accessing data in storage that is corrupted using inline assembly.stdError.memOverflowError
- allocating a dynamic memory array with more than 2^64-1 items.stdError.zeroVarError
- calling a function via a function pointer that has not been initialized.
Assertions
From forge-std/std-assertions
.
// Fail a test with a message
fail(string memory err)
// Assert true/false
assertTrue(bool data)
assertTrue(bool data, string memory error)
assertFalse(bool data)
assertFalse(bool data, string memory err)
// Assert equal
assertEq(<type> a, <type> b)
assertEq(<type> a, <type> b, string memory err)
// Asserts `a` is approximately equal to `b` with delta in absolute value.
assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta)
assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err)
// Asserts `a` is approximately equal to `b` with delta in percentage, where `1e18` is 100%.
assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta)
assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err)
Addresses and Keys
// Create a labelled address
address addr = makeAddr(string memory name)
// Create a labelled address with private key
(address addr, uint256 privateKey) = makeAddrAndKey(string memory name)
// Sign data
(uint8 v, bytes32 r, bytes32 s) = vm.sign(uint256 privateKey, bytes32 digest)
Math
From forge-std/std-math
.
// Returns the absolute value of a number.
uint256 v = abs(int256 a)
// Returns the difference between two numbers in absolute value.
uint256 v = delta(uint256 a, uint256 b)
uint256 v = delta(int256 a, int256 b)
// Returns the difference between two numbers in percentage, where `1e18` is 100%.
uint256 v = percentDelta(uint256 a, uint256 b)
uint256 v = percentDelta(int256 a, int256 b)
Fuzzing
Use vm.assume()
to specify conditions for inputs. It should only be used for narrow checks:
function testSomething(uint256 v) public {
vm.assume(v != 0);
require(v != 0);
...
}
Use bound()
to restrict inputs to a certain range:
function testSomething(uint256 v) public {
v = bound(v, 100, 500);
require(v >= 100 && v <= 500);
...
}