Files
gh-tenequm-claude-plugins-f…/skills/skill/references/configuration.md
2025-11-30 09:01:14 +08:00

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