8.4 KiB
8.4 KiB
Foundry Configuration Reference
Complete reference for foundry.toml configuration options.
Basic Structure
# Default profile
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
# Additional profiles
[profile.ci]
# CI-specific overrides
[profile.production]
# Production build settings
Project Structure
[profile.default]
# Source directories
src = "src" # Contract sources
test = "test" # Test files
script = "script" # Deployment scripts
out = "out" # Compiled output
libs = ["lib"] # Dependency directories
cache_path = "cache" # Compilation cache
# Remappings (alternative to remappings.txt)
remappings = [
"@openzeppelin/=lib/openzeppelin-contracts/",
"@solmate/=lib/solmate/src/",
"forge-std/=lib/forge-std/src/"
]
Compiler Settings
[profile.default]
# Solidity version
solc = "0.8.30" # Exact version
# solc = "^0.8.0" # Version range
# auto_detect_solc = true # Auto-detect from pragmas
# EVM version
evm_version = "prague" # Target EVM version
# Options: homestead, tangerineWhistle, spuriousDragon, byzantium,
# constantinople, petersburg, istanbul, berlin, london,
# paris, shanghai, cancun, prague
# Optimizer
optimizer = true
optimizer_runs = 200 # Optimize for ~200 runs
via_ir = false # Use IR-based compilation
# Output
extra_output = ["abi", "evm.bytecode", "storageLayout"]
extra_output_files = ["abi", "storageLayout"]
# Bytecode hash
bytecode_hash = "ipfs" # ipfs, bzzr1, or none
cbor_metadata = true # Include CBOR metadata
Testing Configuration
[profile.default]
# Verbosity (0-5)
verbosity = 2
# Gas settings
gas_limit = 9223372036854775807
gas_price = 0
block_base_fee_per_gas = 0
tx_origin = "0x0000000000000000000000000000000000000001"
# Block settings
block_coinbase = "0x0000000000000000000000000000000000000000"
block_timestamp = 1
block_number = 1
block_difficulty = 0
block_gas_limit = 30000000
chain_id = 31337
# Sender
sender = "0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38"
# Memory limit (bytes)
memory_limit = 33554432 # 32 MB
# Show gas reports
gas_reports = ["*"] # All contracts
# gas_reports = ["MyContract", "OtherContract"]
gas_reports_ignore = []
# Fail test if gas exceeds this limit
# gas_report_fail_on_increase = true
Fuzz Testing
[profile.default]
# Number of fuzz runs
fuzz.runs = 256
# Seed for deterministic fuzzing
fuzz.seed = "0x1234"
# Maximum test rejects before failing
fuzz.max_test_rejects = 65536
# Dictionary weight (how much to use discovered values)
fuzz.dictionary_weight = 40
# Include push bytes
fuzz.include_push_bytes = true
# Include storage
fuzz.include_storage = true
# Show logs
fuzz.show_logs = false
Invariant Testing
[profile.default]
# Number of runs (sequences)
invariant.runs = 256
# Depth (calls per run)
invariant.depth = 15
# Fail on revert
invariant.fail_on_revert = false
# Call override
invariant.call_override = false
# Dictionary weight
invariant.dictionary_weight = 80
# Include storage
invariant.include_storage = true
# Include push bytes
invariant.include_push_bytes = true
# Shrink run limit
invariant.shrink_run_limit = 5000
# Max fuzz dictionary addresses
invariant.max_fuzz_dictionary_addresses = 15
# Max fuzz dictionary values
invariant.max_fuzz_dictionary_values = 10
# Gas limit
invariant.gas_limit = 9223372036854775807
Fork Testing
[profile.default]
# Default fork URL
# eth_rpc_url = "https://eth-mainnet.alchemyapi.io/v2/..."
# Fork block number
# fork_block_number = 18000000
# Fork retry backoff
fork_retry_backoff = "0"
# RPC storage caching
rpc_storage_caching = {
chains = "all",
endpoints = "all"
}
# No storage caching
no_storage_caching = false
RPC Endpoints
[rpc_endpoints]
mainnet = "https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
sepolia = "https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_KEY}"
arbitrum = "https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
optimism = "https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
polygon = "https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
base = "https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
# Local
localhost = "http://localhost:8545"
anvil = "http://127.0.0.1:8545"
# Environment variable interpolation
custom = "${CUSTOM_RPC_URL}"
Etherscan Configuration
[etherscan]
mainnet = { key = "${ETHERSCAN_API_KEY}" }
sepolia = { key = "${ETHERSCAN_API_KEY}" }
arbitrum = { key = "${ARBISCAN_API_KEY}" }
optimism = { key = "${OPTIMISTIC_ETHERSCAN_API_KEY}" }
polygon = { key = "${POLYGONSCAN_API_KEY}" }
base = { key = "${BASESCAN_API_KEY}" }
# Custom chain
custom = { key = "${CUSTOM_API_KEY}", url = "https://api.custom-explorer.com/api" }
Formatting
[fmt]
# Line length
line_length = 120
# Tab width
tab_width = 4
# Bracket spacing
bracket_spacing = false
# Int types (preserve, short, long)
int_types = "long"
# Multiline function header
multiline_func_header = "attributes_first"
# Quote style
quote_style = "double"
# Number underscore (preserve, thousands, none)
number_underscore = "preserve"
# Hex underscore
hex_underscore = "remove"
# Single line statement blocks
single_line_statement_blocks = "preserve"
# Override spacing
override_spacing = false
# Wrap comments
wrap_comments = false
# Ignore files
ignore = ["src/external/**"]
# Contract new lines
contract_new_lines = false
# Sort imports
sort_imports = false
Documentation
[doc]
# Output directory
out = "docs"
# Repository link
repository = "https://github.com/user/repo"
# Ignore patterns
ignore = ["src/test/**"]
Profiles
Default Profile
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
optimizer = true
optimizer_runs = 200
CI Profile
[profile.ci]
fuzz.runs = 10000
invariant.runs = 1000
invariant.depth = 100
verbosity = 3
Production Profile
[profile.production]
optimizer = true
optimizer_runs = 1000000
via_ir = true
bytecode_hash = "none"
cbor_metadata = false
Gas Optimization Profile
[profile.gas]
optimizer = true
optimizer_runs = 1000000
gas_reports = ["*"]
Fast Development Profile
[profile.fast]
optimizer = false
fuzz.runs = 100
invariant.runs = 50
no_match_test = "testFork_"
Using Profiles
# Use default profile
forge build
forge test
# Use CI profile
FOUNDRY_PROFILE=ci forge test
# Use production profile
FOUNDRY_PROFILE=production forge build
Environment Variables
# Override any config option
FOUNDRY_SRC=contracts forge build
FOUNDRY_OPTIMIZER=false forge build
FOUNDRY_OPTIMIZER_RUNS=1000000 forge build
FOUNDRY_EVM_VERSION=shanghai forge build
# Common overrides
FOUNDRY_PROFILE=ci # Select profile
FOUNDRY_FUZZ_RUNS=10000 # Fuzz runs
FOUNDRY_INVARIANT_RUNS=1000 # Invariant runs
FOUNDRY_VERBOSITY=3 # Test verbosity
Complete Example
# foundry.toml
[profile.default]
# Project
src = "src"
out = "out"
libs = ["lib"]
test = "test"
script = "script"
# Compiler
solc = "0.8.30"
evm_version = "prague"
optimizer = true
optimizer_runs = 200
# Testing
verbosity = 2
fuzz.runs = 256
fuzz.seed = "0x1234"
invariant.runs = 256
invariant.depth = 50
# Gas
gas_reports = ["*"]
# Output
extra_output = ["storageLayout"]
# Remappings
remappings = [
"@openzeppelin/=lib/openzeppelin-contracts/contracts/",
"forge-std/=lib/forge-std/src/"
]
[profile.ci]
fuzz.runs = 10000
fuzz.seed = "0xdeadbeef"
invariant.runs = 1000
invariant.depth = 100
verbosity = 3
[profile.production]
optimizer = true
optimizer_runs = 1000000
via_ir = true
[profile.local]
optimizer = false
fuzz.runs = 100
[rpc_endpoints]
mainnet = "${MAINNET_RPC_URL}"
sepolia = "${SEPOLIA_RPC_URL}"
arbitrum = "${ARBITRUM_RPC_URL}"
optimism = "${OPTIMISM_RPC_URL}"
base = "${BASE_RPC_URL}"
localhost = "http://127.0.0.1:8545"
[etherscan]
mainnet = { key = "${ETHERSCAN_API_KEY}" }
sepolia = { key = "${ETHERSCAN_API_KEY}" }
arbitrum = { key = "${ARBISCAN_API_KEY}" }
optimism = { key = "${OPTIMISTIC_ETHERSCAN_API_KEY}" }
base = { key = "${BASESCAN_API_KEY}" }
[fmt]
line_length = 120
tab_width = 4
bracket_spacing = false
int_types = "long"
multiline_func_header = "attributes_first"
quote_style = "double"
number_underscore = "thousands"
sort_imports = true