451 lines
8.4 KiB
Markdown
451 lines
8.4 KiB
Markdown
# Foundry Configuration Reference
|
|
|
|
Complete reference for `foundry.toml` configuration options.
|
|
|
|
## Basic Structure
|
|
|
|
```toml
|
|
# Default profile
|
|
[profile.default]
|
|
src = "src"
|
|
out = "out"
|
|
libs = ["lib"]
|
|
|
|
# Additional profiles
|
|
[profile.ci]
|
|
# CI-specific overrides
|
|
|
|
[profile.production]
|
|
# Production build settings
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[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
|
|
|
|
```toml
|
|
[doc]
|
|
# Output directory
|
|
out = "docs"
|
|
|
|
# Repository link
|
|
repository = "https://github.com/user/repo"
|
|
|
|
# Ignore patterns
|
|
ignore = ["src/test/**"]
|
|
```
|
|
|
|
## Profiles
|
|
|
|
### Default Profile
|
|
|
|
```toml
|
|
[profile.default]
|
|
src = "src"
|
|
out = "out"
|
|
libs = ["lib"]
|
|
optimizer = true
|
|
optimizer_runs = 200
|
|
```
|
|
|
|
### CI Profile
|
|
|
|
```toml
|
|
[profile.ci]
|
|
fuzz.runs = 10000
|
|
invariant.runs = 1000
|
|
invariant.depth = 100
|
|
verbosity = 3
|
|
```
|
|
|
|
### Production Profile
|
|
|
|
```toml
|
|
[profile.production]
|
|
optimizer = true
|
|
optimizer_runs = 1000000
|
|
via_ir = true
|
|
bytecode_hash = "none"
|
|
cbor_metadata = false
|
|
```
|
|
|
|
### Gas Optimization Profile
|
|
|
|
```toml
|
|
[profile.gas]
|
|
optimizer = true
|
|
optimizer_runs = 1000000
|
|
gas_reports = ["*"]
|
|
```
|
|
|
|
### Fast Development Profile
|
|
|
|
```toml
|
|
[profile.fast]
|
|
optimizer = false
|
|
fuzz.runs = 100
|
|
invariant.runs = 50
|
|
no_match_test = "testFork_"
|
|
```
|
|
|
|
## Using Profiles
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```toml
|
|
# 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
|
|
```
|