Examples
End-to-end patterns: a cheatcode-driven unit test, a forked-mainnet Cast call, and a scripted deployment.
Third-party documentation. This is independently authored analysis of the public Foundry codebase — not the official docs, and not reviewed or endorsed by the Foundry team.
Examples
Three patterns cover the majority of day-to-day Foundry usage: cheatcode-driven unit tests, forked-network queries, and scripted deployments. Each is deliberately minimal — production code adds access control, events, and error paths on top of the same shapes.
Testing against a live protocol
Configure a fork in foundry.toml or pass --fork-url, then write tests that assume real mainnet state exists. A test can deposit into the real Uniswap router, for example, because Anvil materializes remote storage lazily and impersonation lets you act as any holder.
Scripted deployment
forge script executes a Solidity script's run() function first in simulation (printing full traces and state diffs), then — with --broadcast — replays it as real signed transactions. Because simulation and broadcast share one code path, what you see in the dry run is what gets submitted.
Shell-native interaction
Cast commands compose with standard shell tools: pipe cast call output into jq, resolve selectors with cast 4byte, watch new blocks with cast block --latest. No REPL required.
Examples
Unit test with cheatcodes
// SPDX-License-Identifier: MITpragma solidity ^0.8.20;import {Test} from "forge-std/Test.sol";contract VaultTest is Test {Vault vault;function setUp() public {vault = new Vault();deal(address(this), 100 ether);}function testDepositIncreasesShares() public {vm.prank(alice);uint256 shares = vault.deposit{value: 1 ether}();assertEq(vault.balanceOf(alice), shares);}}
setUp runs fresh before every test. vm.prank impersonates alice for the next call and deal sets an address balance — both are cheatcodes interpreted by the embedded EVM rather than real chain state.
Querying a forked mainnet contract
cast call 0xdAC17F958D2ee523a2206206994597C13D831ec7 \"balanceOf(address)(uint256)" 0x000...dEaD \--rpc-url mainnet
Cast decodes return values using inline ABI signatures — the (uint256) suffix tells it the expected output type so no separate ABI file is needed.
Edge Cases
- Tests run against Anvil's default chain id and genesis unless a fork URL is configured — code asserting on chainid or block.number behaves differently between plain and forked test runs.
- vm.prank applies to exactly one external call; a second call in the same test reverts to the default sender unless vm.startPrank was used.
- Fuzz runs shrink failing inputs, but the reported counterexample depends on the configured [fuzz] seed — reproducing a CI failure locally requires matching the seed and runs values.
