| name | foundry-setup |
| description | Templates and automation for initializing and configuring Foundry projects. Use when setting up new Foundry projects or adding Foundry to existing codebases. |
Foundry Setup Skill
This skill provides templates, scripts, and best practices for setting up Foundry-based Solidity projects.
When to Use
Use this skill when:
- Initializing a new Foundry project
- Adding Foundry to an existing Solidity codebase
- Configuring Foundry settings (optimization, tests, etc.)
- Setting up Foundry in a hybrid Hardhat/Foundry project
- Updating Foundry configuration
Prerequisites: Foundry must be installed (foundryup)
Integration with Framework Detection
Before using this skill, reference the framework-detection skill to:
- Check if Foundry is already configured
- Determine if this is a hybrid setup
- Avoid overwriting existing configuration
Quick Setup
Basic Initialization
# Initialize new Foundry project
forge init my-project
cd my-project
# Or initialize in existing directory
forge init --force
Project Structure
Foundry creates this structure:
project/
├── foundry.toml # Configuration
├── .env.example # Environment variables template
├── lib/ # Dependencies (git submodules)
├── src/ # Contract source files
│ ├── interfaces # Interfaces
│ │ └──ICounter # Example interface
│ └── Counter.sol # Example contract
├── test/ # Test files
│ └── Counter.t.sol # Example test
└── script/ # Deployment scripts
└── Counter.s.sol # Example script
Configuration Templates
foundry.toml
See ./templates/foundry.toml for the complete configuration template.
Key Configuration Sections:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc_version = "0.8.30"
optimizer = true
optimizer_runs = 200
via_ir = false
# Testing
verbosity = 2
fuzz_runs = 256
# Gas reporting
gas_reports = ["*"]
# Formatting
line_length = 120
tab_width = 4
bracket_spacing = false
Environment Variables
See ./templates/.env.example for complete environment variable template.
Essential Variables:
# RPC URLs
MAINNET_RPC_URL=
SEPOLIA_RPC_URL=
ARBITRUM_RPC_URL=
# Private Keys (NEVER commit actual keys)
PRIVATE_KEY=
# Etherscan API Keys
ETHERSCAN_API_KEY=
ARBISCAN_API_KEY=
# Gas Price Settings
GAS_PRICE=
Common Configurations
1. High Optimization for Production
[profile.production]
optimizer = true
optimizer_runs = 10000
via_ir = true
2. Detailed Testing
[profile.test]
verbosity = 3
fuzz_runs = 1000
invariant_runs = 256
3. Gas Optimization Focus
[profile.gas-optimized]
optimizer = true
optimizer_runs = 1000000
via_ir = true
gas_reports = ["*"]
4. Mainnet Forking for Tests
[profile.default]
fork_url = "${MAINNET_RPC_URL}"
fork_block_number = 18000000
Dependencies Management
Adding Libraries
# Add OpenZeppelin contracts
forge install OpenZeppelin/openzeppelin-contracts
# Add Solmate
forge install transmissions11/solmate
# Add Forge Standard Library (included by default)
forge install foundry-rs/forge-std
Remappings
Foundry auto-generates remappings.txt, but you can customize:
@openzeppelin/=lib/openzeppelin-contracts/
@solmate/=lib/solmate/src/
forge-std/=lib/forge-std/src/
Or configure in foundry.toml:
remappings = [
"@openzeppelin/=lib/openzeppelin-contracts/",
"@solmate/=lib/solmate/src/"
]
Initialization Script
See ./scripts/init-foundry.sh for automated setup.
Usage:
# Basic initialization
./scripts/init-foundry.sh
# With project name
./scripts/init-foundry.sh my-project
# In existing directory
./scripts/init-foundry.sh --force
What the script does:
- Checks if Foundry is installed
- Initializes Foundry project
- Copies configuration templates
- Sets up .gitignore
- Installs essential dependencies
- Creates initial directory structure
Hybrid Setup (Foundry + Hardhat)
When adding Foundry to an existing Hardhat project:
1. Initialize Foundry Without Overwriting
# Initialize but don't overwrite existing files
forge init --no-commit
2. Configure Separate Directories
# foundry.toml
[profile.default]
src = "contracts" # Use Hardhat's contracts dir
test = "test/foundry" # Separate Foundry tests
out = "out"
libs = ["node_modules", "lib"] # Include both package managers
3. Update .gitignore
# Foundry
out/
cache/
lib/
# Hardhat
artifacts/
cache/
node_modules/
4. Install Shared Dependencies
# Install via Foundry
forge install OpenZeppelin/openzeppelin-contracts
# Reference in Hardhat
# Add to hardhat.config.js:
# paths: { sources: "./contracts" }
Testing Setup
Basic Test Structure
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import "forge-std/Test.sol";
import "../src/MyContract.sol";
contract MyContractTest is Test {
MyContract public myContract;
function setUp() public {
myContract = new MyContract();
}
function testBasic() public {
// Test implementation
}
function testFuzz_Amount(uint256 amount) public {
// Fuzz test
}
}
Running Tests
# Run all tests
forge test
# Run specific test
forge test --match-test testBasic
# Run with verbosity
forge test -vvvv
# Run with gas reporting
forge test --gas-report
# Run with coverage
forge coverage
Security Best Practices for Private Keys
⚠️ CRITICAL: Never store production private keys in .env files!
Recommended Approaches (in order of preference)
1. Hardware Wallets (Most Secure - Production)
# Deploy using Ledger
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $RPC_URL \
--ledger \
--broadcast
# Deploy using Trezor
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $RPC_URL \
--trezor \
--broadcast
2. Cast Wallet (Recommended - Development & Production)
Create a named keystore:
# Create a new wallet (prompts for password)
cast wallet new ~/.foundry/keystores/deployer
# Import existing private key into keystore
cast wallet import deployer --interactive
Use in deployment:
# Deploy using named account
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $RPC_URL \
--account deployer \
--sender 0xYourAddress \
--broadcast
Update your script to use the account:
contract DeployScript is Script {
function run() external {
// No private key needed - uses --account flag
vm.startBroadcast();
MyContract myContract = new MyContract();
vm.stopBroadcast();
console.log("MyContract deployed to:", address(myContract));
}
}
3. Interactive Private Key (Development Only)
# Prompts for private key (not stored anywhere)
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $RPC_URL \
--private-key-interactive \
--broadcast
4. .env Variables (Development/Testing ONLY)
⚠️ Use ONLY for local development or testnet testing with non-production keys!
contract DeployScript is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
MyContract myContract = new MyContract();
vm.stopBroadcast();
console.log("MyContract deployed to:", address(myContract));
}
}
If using .env:
- ✅ Only use accounts created specifically for development/testing
- ✅ Never reuse production private keys
- ✅ Keep test funds minimal
- ✅ Add .env to .gitignore
- ❌ Never commit .env to version control
- ❌ Never use for mainnet deployments
Deployment Setup
Deploy Commands
# Dry run (simulation)
forge script script/Deploy.s.sol:DeployScript --rpc-url $RPC_URL
# Actual deployment with hardware wallet (RECOMMENDED for production)
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $RPC_URL \
--ledger \
--broadcast \
--verify
# Actual deployment with cast wallet (RECOMMENDED for all deployments)
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $RPC_URL \
--account deployer \
--sender 0xYourAddress \
--broadcast \
--verify
# Development only: with .env private key
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $RPC_URL \
--broadcast \
--verify
Best Practices
- Secure private key management - Use hardware wallets or
cast walletfor all deployments; never store production keys in .env - Use profiles - Create different profiles for dev, test, production
- High optimizer runs for production - Use 10,000+ optimizer runs for deployed contracts
- Comprehensive .env.example - Document all required environment variables (but discourage private keys)
- Git submodules for deps - Let Foundry manage dependencies via git
- Separate test directories - Use
test/foundry/for Foundry tests in hybrid setups - Enable via-ir for optimization - Use
via_ir = truefor complex contracts - Version pin Solidity - Specify exact
solc_versionin foundry.toml
Troubleshooting
Issue: "forge: command not found"
# Install/update Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
Issue: Dependency conflicts in hybrid setup
# Prioritize Foundry libs over node_modules
libs = ["lib", "node_modules"]
Issue: Compilation errors with remappings
# Regenerate remappings
forge remappings > remappings.txt
Issue: Tests not found
# Check test file naming (must end in .t.sol)
mv test/MyTest.sol test/MyTest.t.sol
Quick Reference
| Task | Command | Notes |
|---|---|---|
| Init project | forge init |
Creates new project |
| Add dependency | forge install <repo> |
Uses git submodules |
| Build | forge build |
Compiles contracts |
| Test | forge test |
Runs tests |
| Coverage | forge coverage |
Test coverage |
| Gas report | forge test --gas-report |
Gas usage |
| Format | forge fmt |
Code formatting |
| Deploy | forge script |
Run deployment |
| Verify | forge verify-contract |
Verify on Etherscan |
Template Files
This skill provides the following templates:
./templates/foundry.toml- Complete Foundry configuration./templates/.env.example- Environment variables template
Scripts
This skill provides the following scripts:
./scripts/init-foundry.sh- Automated project initialization
Next Steps After Setup:
- Configure
foundry.tomlfor your specific needs - Copy
.env.exampleto.envand fill in values - Install required dependencies with
forge install - Write contracts in
src/ - Write tests in
test/ - Run
forge testto verify setup