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
bash
# 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
bash
# 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
toml
[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
solidity
// 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
solidity
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
solidity
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
solidity
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
bash
# 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
bash
# 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
bash
# 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
bash
# 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
bash
# 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
bash
# 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
solidity
// 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
bash
# 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
bash
# 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 framework - •
skills/echidna-fuzzer/SKILL.md- Advanced fuzzing - •
skills/gas-optimization/SKILL.md- Gas optimization - •Foundry Book