protocols/foundry-guide
Foundry Development Framework Guide
ethereumguide🏛️ Officialconfidence highhealth 100%
v1.0.0·Updated 3/20/2026
Installation
curl -L https://foundry.paradigm.xyz | bash
foundryup
Project Structure
my-project/
├── src/ # Contracts
├── test/ # Tests (*.t.sol)
├── script/ # Deployment scripts (*.s.sol)
├── lib/ # Dependencies (git submodule)
└── foundry.toml
Writing Tests (Solidity-native)
// test/MyToken.t.sol
import "forge-std/Test.sol";
import "../src/MyToken.sol";
contract MyTokenTest is Test {
MyToken token;
address alice = makeAddr("alice");
address bob = makeAddr("bob");
function setUp() public {
token = new MyToken(1000e18);
deal(address(token), alice, 100e18); // Give alice 100 tokens
}
function test_transfer() public {
vm.prank(alice); // Impersonate alice
token.transfer(bob, 10e18);
assertEq(token.balanceOf(bob), 10e18);
}
// Fuzz testing
function testFuzz_transfer(uint256 amount) public {
amount = bound(amount, 1, 100e18);
vm.prank(alice);
token.transfer(bob, amount);
assertEq(token.balanceOf(bob), amount);
}
}
Cheatcodes Quick Reference
vm.prank(address) // Impersonate address for next call
vm.startPrank(address) // Continuously impersonate until stopPrank()
vm.deal(address, amount) // Set ETH balance
deal(token, address, amount) // Set ERC20 balance
vm.warp(timestamp) // Set block timestamp
vm.roll(blockNumber) // Set block number
vm.expectRevert("msg") // Expect revert
vm.expectEmit(true, true, false, true) // Expect event
vm.createFork(rpcUrl) // Create fork
vm.selectFork(forkId) // Switch fork
Deployment Script
// script/Deploy.s.sol
import "forge-std/Script.sol";
contract Deploy is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
MyToken token = new MyToken(1000000e18);
console.log("Token:", address(token));
vm.stopBroadcast();
}
}
forge script script/Deploy.s.sol --rpc-url $SEPOLIA_RPC --broadcast --verify
cast Common Commands
cast call $CONTRACT "balanceOf(address)(uint256)" $ADDRESS # Call read-only function
cast send $CONTRACT "transfer(address,uint256)" $TO $AMOUNT --private-key $KEY
cast abi-encode "f(address,uint256)" 0x... 100
cast storage $CONTRACT 0 # Read slot 0
cast code $CONTRACT # Read bytecode
cast 4byte 0xa9059cbb # Decode function selector
Common Commands
forge build
forge test -vvv # Verbose output
forge test --match-test test_transfer
forge coverage
forge snapshot # Gas snapshot
forge fmt # Format
Hardhat vs Foundry Selection
| Scenario | Recommended |
|---|---|
| Rapid prototyping | Foundry |
| Complex JS/TS logic | Hardhat |
| Fuzz/Invariant testing | Foundry |
| Deep frontend integration | Hardhat |
| Gas optimization analysis | Foundry |