Babysitter foundry-framework
Expert usage of Foundry (Forge, Cast, Anvil, Chisel) for smart contract development, testing, and deployment. Includes fuzzing, gas reporting, local development, and deployment scripting capabilities.
install
source · Clone the upstream repo
git clone https://github.com/a5c-ai/babysitter
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/a5c-ai/babysitter "$T" && mkdir -p ~/.claude/skills && cp -r "$T/library/specializations/cryptography-blockchain/skills/foundry-framework" ~/.claude/skills/a5c-ai-babysitter-foundry-framework && rm -rf "$T"
manifest:
library/specializations/cryptography-blockchain/skills/foundry-framework/SKILL.mdsource content
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 |
|---|---|
| Full development |
| Fuzzing and invariant testing |
| Property-based testing |
| Gas profiling |
| All DeFi processes | Testing and deployment |
Best Practices
- Use
before committingforge fmt - 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
- Alternative frameworkskills/hardhat-framework/SKILL.md
- Advanced fuzzingskills/echidna-fuzzer/SKILL.md
- Gas optimizationskills/gas-optimization/SKILL.md- Foundry Book