# Foundry Cheatcodes You're Probably Not Using
Most Foundry users know vm.prank and vm.expectRevert. But Forge ships with 100+ cheatcodes, many of which are incredibly powerful for edge case testing, fuzzing, and mainnet fork simulations.
Here are 10 underused cheatcodes that will level up your testing.
1. vm.assume — Constrain Fuzz Inputs
When fuzzing, you often need to exclude invalid inputs. Instead of require, use vm.assume:
Before
function testDeposit(uint256 amount) public {
require(amount > 0 && amount < 1e30); // BAD — wastes fuzz runs
vault.deposit(amount);
}
After
function testDeposit(uint256 amount) public {
vm.assume(amount > 0 && amount < 1e30);
vault.deposit(amount);
}
vm.assume tells the fuzzer to discard invalid inputs instead of counting them as passing tests. This gives you better coverage.
Advanced: Multiple Constraints
function testSwap(uint256 amountIn, uint256 reserveA, uint256 reserveB) public {
vm.assume(amountIn > 1000);
vm.assume(reserveA > 1e18 && reserveA < 1e24);
vm.assume(reserveB > 1e18 && reserveB < 1e24);
vm.assume(reserveA != reserveB); // Avoid edge case
// Test swap logic
}
2. vm.store — Manipulate Storage Directly
Need to set up complex state without going through external calls? Use vm.store:
function testLiquidation() public {
// Manually set user balance in storage slot 3
bytes32 slot = keccak256(abi.encode(address(user), 3));
vm.store(address(token), slot, bytes32(uint256(1000e18)));
assertEq(token.balanceOf(user), 1000e18);
}
This is useful for:
- Setting balances without minting
- Manipulating internal state for edge case tests
- Bypassing access control in test setup
3. vm.mockCall — Mock External Calls
Want to test behavior when an external call returns a specific value? Use vm.mockCall:
function testOracleFailure() public {
// Mock oracle to return stale price
vm.mockCall(
address(oracle),
abi.encodeWithSelector(IOracle.getPrice.selector),
abi.encode(0) // Return 0
);
vm.expectRevert("Stale price");
vault.liquidate(user);
}
This lets you simulate external failures without deploying mock contracts.
Advanced: Conditional Mocks
function testConditionalMock() public {
// Mock returns different values based on input
vm.mockCall(
address(oracle),
abi.encodeWithSelector(IOracle.getPrice.selector, tokenA),
abi.encode(1000e18)
);
vm.mockCall(
address(oracle),
abi.encodeWithSelector(IOracle.getPrice.selector, tokenB),
abi.encode(2000e18)
);
assertEq(oracle.getPrice(tokenA), 1000e18);
assertEq(oracle.getPrice(tokenB), 2000e18);
}
4. vm.expectEmit — Verify Event Data
Most people use vm.expectEmit to check that an event was emitted. But you can also verify event data:
function testTransfer() public {
vm.expectEmit(true, true, false, true);
emit Transfer(alice, bob, 100); // Expected event
token.transfer(bob, 100); // Should emit matching event
}
The four booleans control what to check:
Advanced: Multiple Events
function testMultipleEvents() public {
vm.expectEmit(true, true, false, true);
emit Approval(alice, bob, 100);
vm.expectEmit(true, true, false, true);
emit Transfer(alice, bob, 100);
token.transferFrom(alice, bob, 100);
}
5. vm.recordLogs — Capture Events for Inspection
Need to inspect event data programmatically? Use vm.recordLogs:
function testEventData() public {
vm.recordLogs();
vault.deposit(100);
Vm.Log[] memory logs = vm.getRecordedLogs();
assertEq(logs.length, 1);
assertEq(logs[0].topics[0], keccak256("Deposit(address,uint256)"));
}
This is useful for testing event-driven systems like indexers.
6. vm.snapshot and vm.revertTo — Save and Restore State
Testing multiple scenarios from the same starting state? Use snapshots:
function testScenarios() public {
// Setup
vault.deposit(1000);
uint256 snapshot = vm.snapshot();
// Scenario 1: withdraw succeeds
vault.withdraw(500);
assertEq(vault.balanceOf(address(this)), 500);
vm.revertTo(snapshot);
// Scenario 2: withdraw fails
vm.expectRevert("Insufficient balance");
vault.withdraw(2000);
}
This is much faster than re-running setup code.
7. vm.warp and vm.roll — Time Travel
Need to test time-dependent logic? Use vm.warp and vm.roll:
function testVesting() public {
vault.startVesting(1000, 365 days);
// Fast forward 180 days
vm.warp(block.timestamp + 180 days);
uint256 vested = vault.vestedAmount();
assertApproxEqRel(vested, 500, 0.01e18); // ~500, 1% tolerance
}
vm.warp(timestamp)— setblock.timestamp
vm.roll(blockNumber)— setblock.number
8. vm.chainId — Test Multi-Chain Logic
Testing cross-chain signatures or chain-specific logic? Use vm.chainId:
function testChainIdValidation() public {
vm.chainId(1); // Mainnet
assertTrue(bridge.isChainSupported());
vm.chainId(999); // Unsupported chain
assertFalse(bridge.isChainSupported());
}
9. vm.sign and vm.signCompact — Generate Signatures
Need to test EIP-712 signatures? Use vm.sign:
function testPermit() public {
uint256 privateKey = 0x1234;
address signer = vm.addr(privateKey);
bytes32 digest = keccak256(abi.encodePacked(
"\x19\x01",
token.DOMAIN_SEPARATOR(),
keccak256(abi.encode(
token.PERMIT_TYPEHASH(),
signer,
spender,
amount,
nonce,
deadline
))
));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
token.permit(signer, spender, amount, deadline, v, r, s);
}
For compact signatures (EIP-2098), use vm.signCompact.
10. vm.createSelectFork — Fork Multiple Chains
Testing cross-chain interactions? Fork multiple chains in the same test:
function testCrossChain() public {
// Fork Ethereum mainnet
uint256 ethFork = vm.createFork("https://eth-mainnet.g.alchemy.com/v2/...");
// Fork Arbitrum
uint256 arbFork = vm.createFork("https://arb-mainnet.g.alchemy.com/v2/...");
// Switch to Ethereum
vm.selectFork(ethFork);
uint256 ethBalance = USDC.balanceOf(user);
// Switch to Arbitrum
vm.selectFork(arbFork);
uint256 arbBalance = USDC.balanceOf(user);
assertGt(ethBalance, arbBalance);
}
This is incredibly useful for testing bridges and cross-chain protocols.
Summary
These 10 cheatcodes unlock advanced testing patterns:
vm.assume — constrain fuzz inputsvm.store — manipulate storagevm.mockCall — mock external callsvm.expectEmit — verify event datavm.recordLogs — capture eventsvm.snapshot/revertTo — save and restore statevm.warp/roll — time travelvm.chainId — test multi-chain logicvm.sign — generate signaturesvm.createSelectFork — fork multiple chainsMaster these, and your test suite will catch bugs that others miss.
Full cheatcode reference: book.getfoundry.sh/cheatcodes