Foundry Framework Skill
Expert-level usage of Foundry, the blazing fast, portable, and modular toolkit for Ethereum application development.
Capabilities
- Forge Testing: Write and run Solidity tests with fuzzing
- Gas Optimization: Generate detailed gas reports and snapshots
- Local Development: Use Anvil for local blockchain
- Chain Interaction: Execute Cast commands for on-chain operations
- Project Configuration: Set up foundry.toml for projects
- Deployment Scripts: Write and run forge scripts
- REPL Debugging: Use Chisel for Solidity exploration
Installation
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
# Update to latest
foundryup
# Verify installation
forge --version
cast --version
anvil --version
chisel --version
Project Setup
Initialize Project
# New project
forge init my_project
cd my_project
# Add dependencies
forge install OpenZeppelin/openzeppelin-contracts
forge install foundry-rs/forge-std
foundry.toml Configuration
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc = "0.8.20"
optimizer = true
optimizer_runs = 200
via_ir = false
[profile.default.fuzz]
runs = 256
max_test_rejects = 65536
seed = "0x1234"
[profile.default.invariant]
runs = 256
depth = 15
fail_on_revert = false
[profile.ci]
fuzz = { runs = 10000 }
invariant = { runs = 1000, depth = 50 }
[rpc_endpoints]
mainnet = "${MAINNET_RPC_URL}"
sepolia = "${SEPOLIA_RPC_URL}"
arbitrum = "${ARBITRUM_RPC_URL}"
[etherscan]
mainnet = { key = "${ETHERSCAN_API_KEY}" }
sepolia = { key = "${ETHERSCAN_API_KEY}" }
Forge Testing
Basic Test
// test/Counter.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/Counter.sol";
contract CounterTest is Test {
Counter public counter;
function setUp() public {
counter = new Counter();
counter.setNumber(0);
}
function test_Increment() public {
counter.increment();
assertEq(counter.number(), 1);
}
function testFail_Underflow() public {
counter.decrement();
}
}
Fuzz Testing
contract FuzzTest is Test {
function testFuzz_SetNumber(uint256 x) public {
counter.setNumber(x);
assertEq(counter.number(), x);
}
function testFuzz_BoundedInput(uint256 x) public {
x = bound(x, 1, 100);
// x is now between 1 and 100
}
}
Invariant Testing
contract InvariantTest is Test {
Counter public counter;
function setUp() public {
counter = new Counter();
targetContract(address(counter));
}
function invariant_NumberNeverNegative() public {
assertTrue(counter.number() >= 0);
}
function invariant_NumberUnderMax() public {
assertTrue(counter.number() < type(uint256).max);
}
}
Fork Testing
contract ForkTest is Test {
function setUp() public {
// Fork mainnet at specific block
vm.createSelectFork("mainnet", 18000000);
}
function test_MainnetState() public {
// Interact with mainnet contracts
IERC20 dai = IERC20(0x6B175474E89094C44Da98b954EescdeCB5c811d7);
uint256 balance = dai.balanceOf(address(this));
}
}
Forge Commands
# Build project
forge build
# Run tests
forge test
# Run tests with verbosity
forge test -vvvv
# Run specific test
forge test --match-test testFuzz_SetNumber
# Run tests with gas report
forge test --gas-report
# Generate gas snapshot
forge snapshot
# Compare gas snapshots
forge snapshot --diff
# Coverage
forge coverage
# Format code
forge fmt
Cast Commands
Read Chain Data
# Get ETH balance
cast balance 0x... --rpc-url $RPC
# Read contract storage
cast storage 0x... 0 --rpc-url $RPC
# Call view function
cast call 0x... "balanceOf(address)" 0x... --rpc-url $RPC
# Decode calldata
cast calldata-decode "transfer(address,uint256)" 0x...
Send Transactions
# Send ETH
cast send 0x... --value 1ether --rpc-url $RPC --private-key $KEY
# Call contract function
cast send 0x... "transfer(address,uint256)" 0x... 1000 --rpc-url $RPC --private-key $KEY
Utility Commands
# Convert units
cast to-wei 1 ether
cast from-wei 1000000000000000000
# Compute function selector
cast sig "transfer(address,uint256)"
# Get ABI
cast abi-encode "transfer(address,uint256)" 0x... 100
# Decode ABI
cast abi-decode "balanceOf(address)(uint256)" 0x...
Anvil Local Node
# Start local node
anvil
# Start with specific chain ID
anvil --chain-id 31337
# Fork mainnet
anvil --fork-url $MAINNET_RPC
# Fork at specific block
anvil --fork-url $MAINNET_RPC --fork-block-number 18000000
# Preload accounts
anvil --accounts 20 --balance 10000
Anvil RPC
# Impersonate account
cast rpc anvil_impersonateAccount 0x... --rpc-url http://localhost:8545
# Set balance
cast rpc anvil_setBalance 0x... 0x1000000000000000000 --rpc-url http://localhost:8545
# Mine blocks
cast rpc anvil_mine 10 --rpc-url http://localhost:8545
# Set block timestamp
cast rpc evm_setNextBlockTimestamp 1700000000 --rpc-url http://localhost:8545
Deployment Scripts
Script Example
// script/Deploy.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Script.sol";
import "../src/Counter.sol";
contract DeployScript is Script {
function setUp() public {}
function run() public {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
Counter counter = new Counter();
counter.setNumber(42);
vm.stopBroadcast();
console.log("Counter deployed at:", address(counter));
}
}
Run Scripts
# Simulate deployment
forge script script/Deploy.s.sol --rpc-url $RPC
# Deploy to network
forge script script/Deploy.s.sol --rpc-url $RPC --broadcast
# Verify on Etherscan
forge script script/Deploy.s.sol --rpc-url $RPC --broadcast --verify
Chisel REPL
# Start Chisel
chisel
# In REPL
> uint256 x = 100
> x * 2
200
> address(this)
0x...
Process Integration
| Process | Purpose |
|---------|---------|
| smart-contract-development-lifecycle.js | Full development |
| smart-contract-fuzzing.js | Fuzzing and invariant testing |
| invariant-testing.js | Property-based testing |
| gas-optimization.js | Gas profiling |
| All DeFi processes | Testing and deployment |
Best Practices
- Use
forge fmtbefore committing - Maintain gas snapshots for regression testing
- Use fork testing for integration tests
- Set appropriate fuzz runs for CI
- Use profile-based configuration
- Keep foundry.toml in version control
See Also
skills/hardhat-framework/SKILL.md- Alternative frameworkskills/echidna-fuzzer/SKILL.md- Advanced fuzzingskills/gas-optimization/SKILL.md- Gas optimization- Foundry Book