# foundry - Ethereum Development Framework {/* Auto-generated benchmark table from 1/23/2026. Do not edit manually. */} Baseline: [v1.3.6](https://github.com/foundry-rs/foundry/releases/tag/v1.3.6) Latest: [v1.4.0](https://github.com/foundry-rs/foundry/releases/tag/v1.4.0) Learn more about what went into the latest release [here](/releases)
Repository Forge Test Forge Fuzz Test Forge Test (Isolated) Forge Build (No Cache) Forge Build (With Cache) Forge Coverage
[Uniswap-v4-core](https://github.com/Uniswap/v4-core) 7.27s /
6.13s
↓15.68%
6.84s /
6.20s
↓9.36%
7.22s /
7.71s
↑6.79%
2m 3.8s /
2m 5.3s
↑1.21%
0.133s /
0.127s
↓4.51%
1m 34.8s /
1m 30.3s
↓4.75%
[ithacaxyz-account](https://github.com/ithacaxyz/account) 3.17s /
2.94s
↓7.26%
3.18s /
3.02s
↓5.03%
9.16s /
9.08s
↓0.87%
0.156s /
0.113s
↓27.56%
14.91s /
13.34s
↓10.53%
[solady](https://github.com/Vectorized/solady) 2.28s /
2.10s
↓7.89%
2.39s /
2.24s
↓6.28%
2.26s /
2.41s
↑6.64%
14.62s /
14.69s
↑0.48%
0.089s /
0.094s
↑5.62%
[sparkdotfi-spark-psm](https://github.com/sparkdotfi/spark-psm) 43.04s /
44.08s
↑2.42%
3.07s /
2.72s
↓11.40%
45.53s /
50.49s
↑10.89%
13.17s /
13.14s
↓0.23%
0.173s /
0.131s
↓24.28%
3m 49.3s /
3m 40.2s
↓3.97%
import BenchmarksTable from "./benches.mdx"; ## Foundry Benchmarks This page shows the latest performance benchmarks for Foundry across different repositories. The benchmarks are automatically updated from the [Foundry repository](https://github.com/foundry-rs/foundry/blob/master/benches/LATEST.md). ### Performance Overview The table below shows benchmark results comparing different versions of Foundry. Each cell displays the baseline time / latest release time, followed by the percentage change. ### Benchmark Types #### Forge Test Command: [`forge test`](/forge/tests/overview) Measures the standard test execution time. Runs all the tests in the repository. #### Forge Fuzz Test Command: [`forge test --match-test "test[^(]*\([^)]+\)"`](/forge/advanced-testing/fuzz-testing) Measure the execution time for fuzz tests. #### Forge Test Isolated Command: [`forge test --isolate`](/forge/reference/test) Measures the execution time of tests in `isolate` mode. In isolation mode all top-level calls are executed as a separate transaction in a separate EVM context, enabling more precise gas accounting and transaction state changes. #### Forge Build (No Cache) Command: [`forge build`](/forge/reference/build) Measures compilation time on a clean repository i.e no cache available. #### Forge Build (With Cache) Command: [`forge build`](/forge/reference/build) Measures execution time for `forge build` in presense of full cache. In this case, compilation is skipped and `forge` only check whether the cache is clean or marked as dirty. #### Forge Coverage Command: [`forge coverage --ir-minimum`](/forge/reference/coverage) Measures the time taken to analyze and collect test coverage reports. It is important to note that this time includes compilation time as well. Before analyzing for coverage every project is recompiled with configuration that will result in accurate coverage reports. ## v1.6.0-rc1 \[January 22, 2026] ### Cast Features * feat(cast): tempo nonce keys ([#12977](https://github.com/foundry-rs/foundry/pull/12977)) by [@onbjerg](https://github.com/onbjerg) ### Performance improvements * perf(forge): parallelize stateless fuzzing ([#12713](https://github.com/foundry-rs/foundry/pull/12713)) by [@DaniPopes](https://github.com/DaniPopes) ### Other * added MONAD\_SYSTEM\_ADDRESS ([#12585](https://github.com/foundry-rs/foundry/pull/12585)) by [@Jayakumar2812](https://github.com/Jayakumar2812) * chore(anvil): deprecate `getBlobSidecars` Beacon API endpoint ([#12568](https://github.com/foundry-rs/foundry/pull/12568)) by [@mablr](https://github.com/mablr) * feat(anvil): add `eth_fillTransaction` support ([#12595](https://github.com/foundry-rs/foundry/pull/12595)) by [@mablr](https://github.com/mablr) * chore(deps): bump crate-ci/typos from 1.39.0 to 1.39.2 ([#12593](https://github.com/foundry-rs/foundry/pull/12593)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump taiki-e/install-action from 2.62.49 to 2.62.52 ([#12592](https://github.com/foundry-rs/foundry/pull/12592)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump DeterminateSystems/determinate-nix-action from 3.13.0 to 3.13.1 ([#12594](https://github.com/foundry-rs/foundry/pull/12594)) by [@dependabot](https://github.com/dependabot)\[bot] * fix(`ci`): ignore `number_prefix` is unmaintained in `cargo deny` ([#12598](https://github.com/foundry-rs/foundry/pull/12598)) by [@zerosnacks](https://github.com/zerosnacks) * fix: `eth_fillTransaction` response ([#12597](https://github.com/foundry-rs/foundry/pull/12597)) by [@jxom](https://github.com/jxom) * chore: bump alloy-chains ([#12606](https://github.com/foundry-rs/foundry/pull/12606)) by [@grandizzy](https://github.com/grandizzy) * fix: correct per-variable bytes/string identification and remove nested scan ([#12603](https://github.com/foundry-rs/foundry/pull/12603)) by [@Bashmunta](https://github.com/Bashmunta) * refactor(sol-macro-gen): remove unused artifacts\_path from MultiSolMacroGen ([#12578](https://github.com/foundry-rs/foundry/pull/12578)) by [@Fibonacci747](https://github.com/Fibonacci747) * refactor: simplify gas snapshot handling in cheatcodes ([#12605](https://github.com/foundry-rs/foundry/pull/12605)) by [@Sharilleed223](https://github.com/Sharilleed223) * fix(verify): mismatch between strip\_prefix and strip\_suffix ([#12563](https://github.com/foundry-rs/foundry/pull/12563)) by [@Bashmunta](https://github.com/Bashmunta) * fix(cast): handle errors in list\_local\_senders() ([#12419](https://github.com/foundry-rs/foundry/pull/12419)) by [@DeVikingMark](https://github.com/DeVikingMark) * feat!(`forge script`): add `--interactive` flag for deploying with a single keypair ([#12608](https://github.com/foundry-rs/foundry/pull/12608)) by [@zerosnacks](https://github.com/zerosnacks) * chore(deps): unpin from revm patch ([#12609](https://github.com/foundry-rs/foundry/pull/12609)) by [@zerosnacks](https://github.com/zerosnacks) * chore: bump alloy chains ([#12613](https://github.com/foundry-rs/foundry/pull/12613)) by [@grandizzy](https://github.com/grandizzy) * docs: remove duplicate foundry-compilers link reference in README ([#12575](https://github.com/foundry-rs/foundry/pull/12575)) by [@MamunC0der](https://github.com/MamunC0der) * feat(anvil): extend Content-Type support on Beacon API ([#12611](https://github.com/foundry-rs/foundry/pull/12611)) by [@mablr](https://github.com/mablr) * docs: clean up config docs ([#12296](https://github.com/foundry-rs/foundry/pull/12296)) by [@onbjerg](https://github.com/onbjerg) * feat: support solc prereleases ([#12599](https://github.com/foundry-rs/foundry/pull/12599)) by [@grandizzy](https://github.com/grandizzy) * feat: use different gas calc for monad mainnet ([#12615](https://github.com/foundry-rs/foundry/pull/12615)) by [@QEDK](https://github.com/QEDK) * chore: disable failing test ([#12620](https://github.com/foundry-rs/foundry/pull/12620)) by [@grandizzy](https://github.com/grandizzy) * fix: correct comment for Git::has\_submodules and remove\_contract ([#12530](https://github.com/foundry-rs/foundry/pull/12530)) by [@sashass1315](https://github.com/sashass1315) * chore(anvil): use `FillTransaction` from alloy ([#12622](https://github.com/foundry-rs/foundry/pull/12622)) by [@mablr](https://github.com/mablr) * feat(cast): wallet sign-auth --self-broadcast ([#12624](https://github.com/foundry-rs/foundry/pull/12624)) by [@0xferrous](https://github.com/0xferrous) * refactor(anvil): use alloy envelope macro ([#12406](https://github.com/foundry-rs/foundry/pull/12406)) by [@mablr](https://github.com/mablr) * feat(forge): warp and roll on invariant tx ([#12616](https://github.com/foundry-rs/foundry/pull/12616)) by [@grandizzy](https://github.com/grandizzy) * feat(cast): accept multiple 7702 authorizations ([#12627](https://github.com/foundry-rs/foundry/pull/12627)) by [@0xferrous](https://github.com/0xferrous) * refactor(anvil): remove `TypedTransaction::as_legacy()` method ([#12633](https://github.com/foundry-rs/foundry/pull/12633)) by [@mablr](https://github.com/mablr) * refactor(anvil): remove `TypedTransaction::blob_gas()` method ([#12632](https://github.com/foundry-rs/foundry/pull/12632)) by [@mablr](https://github.com/mablr) * refactor(anvil): remove `TypedTransaction::essentials()` method ([#12631](https://github.com/foundry-rs/foundry/pull/12631)) by [@mablr](https://github.com/mablr) * chore(deps): weekly `cargo update` ([#12642](https://github.com/foundry-rs/foundry/pull/12642)) by [@github-actions](https://github.com/github-actions)\[bot] * refactor(anvil): simplify `effective_reward` calculation in `FeeHistoryService` ([#12640](https://github.com/foundry-rs/foundry/pull/12640)) by [@mablr](https://github.com/mablr) * refactor(anvil): use alloy's `effective_gas_price` in `Backend::mined_transaction_receipt` ([#12639](https://github.com/foundry-rs/foundry/pull/12639)) by [@mablr](https://github.com/mablr) * chore(deps): bump actions/checkout from 5 to 6 ([#12652](https://github.com/foundry-rs/foundry/pull/12652)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump peter-evans/create-pull-request from 7.0.8 to 7.0.9 ([#12653](https://github.com/foundry-rs/foundry/pull/12653)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump DeterminateSystems/determinate-nix-action from 3.13.1 to 3.13.2 ([#12655](https://github.com/foundry-rs/foundry/pull/12655)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump taiki-e/install-action from 2.62.52 to 2.62.57 ([#12654](https://github.com/foundry-rs/foundry/pull/12654)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(tests): bump forge-std version ([#12661](https://github.com/foundry-rs/foundry/pull/12661)) by [@github-actions](https://github.com/github-actions)\[bot] * fix(docs): correct LintContext lifetime in check\_full\_source\_unit example ([#12462](https://github.com/foundry-rs/foundry/pull/12462)) by [@DeVikingMark](https://github.com/DeVikingMark) * chore: aggregate PRs ([#12669](https://github.com/foundry-rs/foundry/pull/12669)) by [@DaniPopes](https://github.com/DaniPopes) * feat: forge verify-bytecode should automatically recompile upon running ([#12651](https://github.com/foundry-rs/foundry/pull/12651)) by [@Jds-23](https://github.com/Jds-23) * chore(anvil): tidy up `anvil::server` module ([#12663](https://github.com/foundry-rs/foundry/pull/12663)) by [@mablr](https://github.com/mablr) * feat(traces): add a -d | --depth flag for verbose traces, like tree ([#12643](https://github.com/foundry-rs/foundry/pull/12643)) by [@tskoyo](https://github.com/tskoyo) * fix(chisel): don't panic on bad pc/memory ([#12674](https://github.com/foundry-rs/foundry/pull/12674)) by [@DaniPopes](https://github.com/DaniPopes) * fix(ci): ignore clippy error: `.exactly_one()` may be added to the standard library in the future on `rustc 1.93.0-nightly` ([#12678](https://github.com/foundry-rs/foundry/pull/12678)) by [@zerosnacks](https://github.com/zerosnacks) * chore(anvil): make `MayImpersonatedTransaction` fields private ([#12681](https://github.com/foundry-rs/foundry/pull/12681)) by [@mablr](https://github.com/mablr) * chore: cast erc20 to follow cast send options ([#12684](https://github.com/foundry-rs/foundry/pull/12684)) by [@grandizzy](https://github.com/grandizzy) * Remove redundant clone when bundling filled transactions ([#12682](https://github.com/foundry-rs/foundry/pull/12682)) by [@soniseth0](https://github.com/soniseth0) * fix: emit console.log on fuzz test last run at verbosity >= 2 ([#12478](https://github.com/foundry-rs/foundry/pull/12478)) by [@avorylli](https://github.com/avorylli) * chore: fix clippy & forge-std external test ([#12698](https://github.com/foundry-rs/foundry/pull/12698)) by [@grandizzy](https://github.com/grandizzy) * chore(deps): weekly `cargo update` ([#12697](https://github.com/foundry-rs/foundry/pull/12697)) by [@github-actions](https://github.com/github-actions)\[bot] * fix(verify): improve error message for unsupported chain in Etherscan verifier ([#12685](https://github.com/foundry-rs/foundry/pull/12685)) by [@DeVikingMark](https://github.com/DeVikingMark) * refactor(anvil): promote anvil's envelope type to foundry-primitives crate ([#12691](https://github.com/foundry-rs/foundry/pull/12691)) by [@mablr](https://github.com/mablr) * chore(cli): remove redundant eth\_rpc\_url insert from EvmArgs::data ([#12701](https://github.com/foundry-rs/foundry/pull/12701)) by [@Snezhkko](https://github.com/Snezhkko) * feat: add XDC Network + SKALE Base support by bumping `alloy-chains` ([#12710](https://github.com/foundry-rs/foundry/pull/12710)) by [@zerosnacks](https://github.com/zerosnacks) * feat(cast): add support for raw transaction data with --data flag in send ([#12712](https://github.com/foundry-rs/foundry/pull/12712)) by [@Jds-23](https://github.com/Jds-23) * fix: correct SerializeMap size hint in RpcEndpoint::serialize ([#12715](https://github.com/foundry-rs/foundry/pull/12715)) by [@Forostovec](https://github.com/Forostovec) * perf: compute literals only once ([#12716](https://github.com/foundry-rs/foundry/pull/12716)) by [@DaniPopes](https://github.com/DaniPopes) * fix: bump svm-rs ([#12728](https://github.com/foundry-rs/foundry/pull/12728)) by [@grandizzy](https://github.com/grandizzy) * deps(`forge init`): update to checkout v6 in default templates ([#12731](https://github.com/foundry-rs/foundry/pull/12731)) by [@zerosnacks](https://github.com/zerosnacks) * fix: add `log` fn support alongside `log_full` fn, follow-up fix for `revm 33` ([#12718](https://github.com/foundry-rs/foundry/pull/12718)) by [@zerosnacks](https://github.com/zerosnacks) * chore(cli): remove useless clap visible aliases ([#12735](https://github.com/foundry-rs/foundry/pull/12735)) by [@mablr](https://github.com/mablr) * refactor(verify): remove redundant String conversion for VerificationType ([#12740](https://github.com/foundry-rs/foundry/pull/12740)) by [@Bashmunta](https://github.com/Bashmunta) * chore: fix serialization map size hint ([#12720](https://github.com/foundry-rs/foundry/pull/12720)) by [@Sharilleed223](https://github.com/Sharilleed223) * fix(anvil): resolve incorrect historical states dump behavior ([#12732](https://github.com/foundry-rs/foundry/pull/12732)) by [@w1tcher](https://github.com/w1tcher) * feat: support cast logs query chunking ([#12692](https://github.com/foundry-rs/foundry/pull/12692)) by [@stevencartavia](https://github.com/stevencartavia) * feat(foundry-primitives): introduce `FoundryNetwork` ([#12722](https://github.com/foundry-rs/foundry/pull/12722)) by [@mablr](https://github.com/mablr) * chore(deps): weekly `cargo update` ([#12751](https://github.com/foundry-rs/foundry/pull/12751)) by [@github-actions](https://github.com/github-actions)\[bot] * deps: bump alloy-chains 0.2.22 ([#12760](https://github.com/foundry-rs/foundry/pull/12760)) by [@onbjerg](https://github.com/onbjerg) * chore(anvil): create `EitherEvm` using `OpEvm` and `EthEvm` factories ([#12764](https://github.com/foundry-rs/foundry/pull/12764)) by [@mablr](https://github.com/mablr) * chore(deps): bump DeterminateSystems/update-flake-lock from e637603d31bed83169f2e56bb475c9dff7af6544 to 45146d6189ea5880a3a07f999952bf21810804f1 ([#12766](https://github.com/foundry-rs/foundry/pull/12766)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump crate-ci/typos from 1.39.2 to 1.40.0 ([#12769](https://github.com/foundry-rs/foundry/pull/12769)) by [@dependabot](https://github.com/dependabot)\[bot] * chore: update to macos14 runner ([#12774](https://github.com/foundry-rs/foundry/pull/12774)) by [@grandizzy](https://github.com/grandizzy) * chore(deps): bump peter-evans/create-pull-request from 7.0.9 to 7.0.11 ([#12770](https://github.com/foundry-rs/foundry/pull/12770)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump docker/metadata-action from 5.9.0 to 5.10.0 ([#12768](https://github.com/foundry-rs/foundry/pull/12768)) by [@dependabot](https://github.com/dependabot)\[bot] * feat(`foundryup`): add Tempo support ([#12775](https://github.com/foundry-rs/foundry/pull/12775)) by [@zerosnacks](https://github.com/zerosnacks) * chore(deps): bump softprops/action-gh-release from 2.4.2 to 2.5.0 ([#12767](https://github.com/foundry-rs/foundry/pull/12767)) by [@dependabot](https://github.com/dependabot)\[bot] * refactor(anvil): use `EvmEnv` in backend/executor ([#12763](https://github.com/foundry-rs/foundry/pull/12763)) by [@mablr](https://github.com/mablr) * feat(forge selectors): cache selectors from abis ([#12742](https://github.com/foundry-rs/foundry/pull/12742)) by [@JuaniRios](https://github.com/JuaniRios) * test: ignore test in isolate ([#12778](https://github.com/foundry-rs/foundry/pull/12778)) by [@DaniPopes](https://github.com/DaniPopes) * docs: fix wrong flag and deprecated command for clippy ([#12780](https://github.com/foundry-rs/foundry/pull/12780)) by [@JuaniRios](https://github.com/JuaniRios) * test: bump solady ([#12781](https://github.com/foundry-rs/foundry/pull/12781)) by [@DaniPopes](https://github.com/DaniPopes) * feat(cast): strip WalletOpts and EtherscanOpts from cast subcommands that dont expect a signer or need etherscan api ([#12705](https://github.com/foundry-rs/foundry/pull/12705)) by [@tskoyo](https://github.com/tskoyo) * fix(forge): failing tests trigger early exit without --fail-fast ([#12785](https://github.com/foundry-rs/foundry/pull/12785)) by [@0xferrous](https://github.com/0xferrous) * fix(primitives): `FoundryTransactionRequest` based on `WithOtherFields` ([#12786](https://github.com/foundry-rs/foundry/pull/12786)) by [@mablr](https://github.com/mablr) * fix: add plasma verifier err msg ([#12790](https://github.com/foundry-rs/foundry/pull/12790)) by [@grandizzy](https://github.com/grandizzy) * docs(config): complete fuzz and invariant sections with 20+ missing options ([#12789](https://github.com/foundry-rs/foundry/pull/12789)) by [@aso20455](https://github.com/aso20455) * refactor(anvil): simplify `determine_base_gas_by_kind` logic ([#12787](https://github.com/foundry-rs/foundry/pull/12787)) by [@mablr](https://github.com/mablr) * fix(verify): handle lack of trailing slash in verifier url ([#12806](https://github.com/foundry-rs/foundry/pull/12806)) by [@onbjerg](https://github.com/onbjerg) * chore(primitives): simplify TxEnv conversions + bump alloy-evm ([#12805](https://github.com/foundry-rs/foundry/pull/12805)) by [@mablr](https://github.com/mablr) * refactor(cheatcodes): avoid duplicate get\_contract\_data calls in stat… ([#12800](https://github.com/foundry-rs/foundry/pull/12800)) by [@aganisgash](https://github.com/aganisgash) * refactor(anvil): use `TransactionBuilder` trait to build tx requests ([#12804](https://github.com/foundry-rs/foundry/pull/12804)) by [@mablr](https://github.com/mablr) * feat(primitives): `get_deposit_tx_parts` helper ([#12808](https://github.com/foundry-rs/foundry/pull/12808)) by [@mablr](https://github.com/mablr) * chore(deps): weekly `cargo update` ([#12811](https://github.com/foundry-rs/foundry/pull/12811)) by [@github-actions](https://github.com/github-actions)\[bot] * fix(anvil): propagate gas estimation errors ([#12813](https://github.com/foundry-rs/foundry/pull/12813)) by [@jxom](https://github.com/jxom) * chore: fmt ([#12816](https://github.com/foundry-rs/foundry/pull/12816)) by [@mattsse](https://github.com/mattsse) * chore: move `FoundryHardfork` into `foundry-evm-core` crate ([#12820](https://github.com/foundry-rs/foundry/pull/12820)) by [@zerosnacks](https://github.com/zerosnacks) * feat(forge): add `--network tempo` flag to `forge init` ([#12819](https://github.com/foundry-rs/foundry/pull/12819)) by [@onbjerg](https://github.com/onbjerg) * refactor(anvil): move receipts logic to foundry-primitives ([#12818](https://github.com/foundry-rs/foundry/pull/12818)) by [@mablr](https://github.com/mablr) * fix: use ConversionError instead of unit type in receipt conversion ([#12824](https://github.com/foundry-rs/foundry/pull/12824)) by [@oooLowNeoNooo](https://github.com/oooLowNeoNooo) * fix(foundryup): strip leading backslash from sha256sum ([#12827](https://github.com/foundry-rs/foundry/pull/12827)) by [@DaniPopes](https://github.com/DaniPopes) * chore(deps): bump actions/download-artifact from 6 to 7 ([#12832](https://github.com/foundry-rs/foundry/pull/12832)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump DeterminateSystems/update-flake-lock from 45146d6189ea5880a3a07f999952bf21810804f1 to 2235257b90962ba68499d64da5b0d1eaa3b46c1e ([#12831](https://github.com/foundry-rs/foundry/pull/12831)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump actions/upload-artifact from 5 to 6 ([#12830](https://github.com/foundry-rs/foundry/pull/12830)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump DeterminateSystems/determinate-nix-action from 3.13.2 to 3.14.0 ([#12829](https://github.com/foundry-rs/foundry/pull/12829)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump actions/cache from 4 to 5 ([#12828](https://github.com/foundry-rs/foundry/pull/12828)) by [@dependabot](https://github.com/dependabot)\[bot] * fix: add assertion on existence of `tempo-std` in template test ([#12833](https://github.com/foundry-rs/foundry/pull/12833)) by [@zerosnacks](https://github.com/zerosnacks) * feat(ci): lint shell scripts ([#12797](https://github.com/foundry-rs/foundry/pull/12797)) by [@o-az](https://github.com/o-az) * test: ignore flaky verification tests ([#12791](https://github.com/foundry-rs/foundry/pull/12791)) by [@onbjerg](https://github.com/onbjerg) * chore(deps): update to soldeer 0.10.0 ([#12835](https://github.com/foundry-rs/foundry/pull/12835)) by [@beeb](https://github.com/beeb) * fix: remove redundant project clone in flatten call ([#12825](https://github.com/foundry-rs/foundry/pull/12825)) by [@forkfury](https://github.com/forkfury) * chore(`cargo deny`): migrate away from `number_prefix` ([#12840](https://github.com/foundry-rs/foundry/pull/12840)) by [@zerosnacks](https://github.com/zerosnacks) * chore(meta): configure issue types in issue forms ([#12850](https://github.com/foundry-rs/foundry/pull/12850)) by [@onbjerg](https://github.com/onbjerg) * fix(forge): fail compilation on unresolved imports ([#12848](https://github.com/foundry-rs/foundry/pull/12848)) by [@subwaycookiecrunch](https://github.com/subwaycookiecrunch) * feat(cast): `--replay-system-txes` / `--sys` arg to cast run system txes ([#12853](https://github.com/foundry-rs/foundry/pull/12853)) by [@grandizzy](https://github.com/grandizzy) * chore: add CastTxSender ([#12834](https://github.com/foundry-rs/foundry/pull/12834)) by [@grandizzy](https://github.com/grandizzy) * fix(anvil): insufficient allowance → insufficient balance ([#12855](https://github.com/foundry-rs/foundry/pull/12855)) by [@anim001k](https://github.com/anim001k) * refactor(primitives): simplify envelope conversion ([#12858](https://github.com/foundry-rs/foundry/pull/12858)) by [@onbjerg](https://github.com/onbjerg) * docs(primitives): add links to tx type docs ([#12857](https://github.com/foundry-rs/foundry/pull/12857)) by [@onbjerg](https://github.com/onbjerg) * chore: bump version 1.5.1 ([#12873](https://github.com/foundry-rs/foundry/pull/12873)) by [@grandizzy](https://github.com/grandizzy) * chore: update dependencies ([#12874](https://github.com/foundry-rs/foundry/pull/12874)) by [@zerosnacks](https://github.com/zerosnacks) * feat(cast): use foundry-primitives types ([#12877](https://github.com/foundry-rs/foundry/pull/12877)) by [@onbjerg](https://github.com/onbjerg) * refactor: split up test-utils util.rs ([#12878](https://github.com/foundry-rs/foundry/pull/12878)) by [@DaniPopes](https://github.com/DaniPopes) * fix(forge): reseed cheatcodes rng in fuzz tests ([#12843](https://github.com/foundry-rs/foundry/pull/12843)) by [@DaniPopes](https://github.com/DaniPopes) * feat(primitives): tempo transaction support ([#12859](https://github.com/foundry-rs/foundry/pull/12859)) by [@onbjerg](https://github.com/onbjerg) * chore(deps): weekly `cargo update` ([#12896](https://github.com/foundry-rs/foundry/pull/12896)) by [@github-actions](https://github.com/github-actions)\[bot] * refactor(script): remove unreachable ENS error branch in simulate() ([#12759](https://github.com/foundry-rs/foundry/pull/12759)) by [@GarmashAlex](https://github.com/GarmashAlex) * docs(lint): add missing lint rules to README ([#12758](https://github.com/foundry-rs/foundry/pull/12758)) by [@dizer-ti](https://github.com/dizer-ti) * chore: clap opt-level 3 ([#12903](https://github.com/foundry-rs/foundry/pull/12903)) by [@DaniPopes](https://github.com/DaniPopes) * fix(coverage): write coverage file even when tests fail ([#12717](https://github.com/foundry-rs/foundry/pull/12717)) by [@0xferrous](https://github.com/0xferrous) * feat(cast): cache Etherscan sources under Foundry cache with temp fallback ([#12025](https://github.com/foundry-rs/foundry/pull/12025)) by [@sashass1315](https://github.com/sashass1315) * feat(lint): reduce default verbosity ([#12901](https://github.com/foundry-rs/foundry/pull/12901)) by [@DaniPopes](https://github.com/DaniPopes) * fix(config): prints error when accessing invalid etherscan config ([#9951](https://github.com/foundry-rs/foundry/pull/9951)) by [@andelf](https://github.com/andelf) * fix(cast): treat threads=0 as logical cores ([#12799](https://github.com/foundry-rs/foundry/pull/12799)) by [@ANtutov](https://github.com/ANtutov) * feat(cast): derive accounts from mnemonic ([#12700](https://github.com/foundry-rs/foundry/pull/12700)) by [@leovct](https://github.com/leovct) * chore(deps): run cargo shear ([#12906](https://github.com/foundry-rs/foundry/pull/12906)) by [@DaniPopes](https://github.com/DaniPopes) * chore: rm mask64 ([#12909](https://github.com/foundry-rs/foundry/pull/12909)) by [@DaniPopes](https://github.com/DaniPopes) * chore: add Config::is\_standalone\_section ([#12910](https://github.com/foundry-rs/foundry/pull/12910)) by [@DaniPopes](https://github.com/DaniPopes) * feat: include actual tx type in unknown transaction error ([#12851](https://github.com/foundry-rs/foundry/pull/12851)) by [@Sharilleed223](https://github.com/Sharilleed223) * chore: remove redundant empty lines ([#12915](https://github.com/foundry-rs/foundry/pull/12915)) by [@mattsse](https://github.com/mattsse) * chore(deps): bump taiki-e/install-action from 2.62.57 to 2.65.1 ([#12920](https://github.com/foundry-rs/foundry/pull/12920)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump DeterminateSystems/determinate-nix-action from 3.14.0 to 3.15.0 ([#12921](https://github.com/foundry-rs/foundry/pull/12921)) by [@dependabot](https://github.com/dependabot)\[bot] * chore: respect configured thread count ([#12923](https://github.com/foundry-rs/foundry/pull/12923)) by [@Sharilleed223](https://github.com/Sharilleed223) * feat: implement Uifmt for foundry primitive types ([#12917](https://github.com/foundry-rs/foundry/pull/12917)) by [@stevencartavia](https://github.com/stevencartavia) * chore: ignore RUSTSEC-2025-0137 ([#12941](https://github.com/foundry-rs/foundry/pull/12941)) by [@mattsse](https://github.com/mattsse) * chore(deps): weekly `cargo update` ([#12940](https://github.com/foundry-rs/foundry/pull/12940)) by [@github-actions](https://github.com/github-actions)\[bot] * fix(chisel): uninitalized variables ([#12937](https://github.com/foundry-rs/foundry/pull/12937)) by [@DaniPopes](https://github.com/DaniPopes) * chore(deps): bump Swatinem/rust-cache from 2.8.1 to 2.8.2 ([#12919](https://github.com/foundry-rs/foundry/pull/12919)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump peter-evans/create-pull-request from 7.0.11 to 8.0.0 ([#12918](https://github.com/foundry-rs/foundry/pull/12918)) by [@dependabot](https://github.com/dependabot)\[bot] * chore: sepolia rpc url ([#12945](https://github.com/foundry-rs/foundry/pull/12945)) by [@grandizzy](https://github.com/grandizzy) * chore(deps): bump crate-ci/typos from 1.40.0 to 1.40.1 ([#12949](https://github.com/foundry-rs/foundry/pull/12949)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump DeterminateSystems/determinate-nix-action from 3.15.0 to 3.15.1 ([#12950](https://github.com/foundry-rs/foundry/pull/12950)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump taiki-e/install-action from 2.65.1 to 2.65.7 ([#12951](https://github.com/foundry-rs/foundry/pull/12951)) by [@dependabot](https://github.com/dependabot)\[bot] * fix(config): err on unknown profile ([#12946](https://github.com/foundry-rs/foundry/pull/12946)) by [@grandizzy](https://github.com/grandizzy) * test: remove duplicate Issue2851 test ([#12953](https://github.com/foundry-rs/foundry/pull/12953)) by [@DaniPopes](https://github.com/DaniPopes) * chore(cheats): make sign(Wallet) pure ([#12912](https://github.com/foundry-rs/foundry/pull/12912)) by [@DaniPopes](https://github.com/DaniPopes) * fix(evm): use timestamp-based blob base fee calculation ([#12959](https://github.com/foundry-rs/foundry/pull/12959)) by [@cakevm](https://github.com/cakevm) * fix(config): reject bare versions in compilation restrictions ([#12955](https://github.com/foundry-rs/foundry/pull/12955)) by [@tefyosL-sol](https://github.com/tefyosL-sol) * Revert "fix(config): err on unknown profile ([#12946](https://github.com/foundry-rs/foundry/pull/12946))" ([#12964](https://github.com/foundry-rs/foundry/pull/12964)) by [@grandizzy](https://github.com/grandizzy) * fix(anvil): use B256 instead of TxHash for block hash parameters ([#12961](https://github.com/foundry-rs/foundry/pull/12961)) by [@PivasDesant](https://github.com/PivasDesant) * feat: add support for constructing tempo tx ([#12972](https://github.com/foundry-rs/foundry/pull/12972)) by [@onbjerg](https://github.com/onbjerg) * feat(anvil): basic tempo tx signing support ([#12974](https://github.com/foundry-rs/foundry/pull/12974)) by [@onbjerg](https://github.com/onbjerg) * chore(meta): update .gitignore ([#12975](https://github.com/foundry-rs/foundry/pull/12975)) by [@DaniPopes](https://github.com/DaniPopes) * chore(deps): remove default features from tempo ([#12976](https://github.com/foundry-rs/foundry/pull/12976)) by [@DaniPopes](https://github.com/DaniPopes) * feat(cast): add tempo tx construction support ([#12973](https://github.com/foundry-rs/foundry/pull/12973)) by [@onbjerg](https://github.com/onbjerg) * fix: use network-specific BaseFeeParams for Optimism in Anvil ([#12944](https://github.com/foundry-rs/foundry/pull/12944)) by [@haythemsellami](https://github.com/haythemsellami) * fix(forge): lookup path artifact if not in available artifacts ([#12927](https://github.com/foundry-rs/foundry/pull/12927)) by [@grandizzy](https://github.com/grandizzy) * chore(deps): weekly `cargo update` ([#12980](https://github.com/foundry-rs/foundry/pull/12980)) by [@github-actions](https://github.com/github-actions)\[bot] * docs: minor readme touchups ([#12983](https://github.com/foundry-rs/foundry/pull/12983)) by [@onbjerg](https://github.com/onbjerg) * chore(tests): bump forge-std version ([#12986](https://github.com/foundry-rs/foundry/pull/12986)) by [@github-actions](https://github.com/github-actions)\[bot] * feat: alias `cast erc20 transfer` to `cast erc20 send` ([#12990](https://github.com/foundry-rs/foundry/pull/12990)) by [@onbjerg](https://github.com/onbjerg) * chore(tests): bump forge-std version ([#12992](https://github.com/foundry-rs/foundry/pull/12992)) by [@github-actions](https://github.com/github-actions)\[bot] * feat(cast): add trace\_transaction and trace\_rawTransaction ([#12788](https://github.com/foundry-rs/foundry/pull/12788)) by [@figtracer](https://github.com/figtracer) * chore(deps): bump taiki-e/install-action from 2.65.7 to 2.65.13 ([#12999](https://github.com/foundry-rs/foundry/pull/12999)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump taiki-e/cache-cargo-install-action from 2.3.1 to 3.0.0 ([#12998](https://github.com/foundry-rs/foundry/pull/12998)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump crate-ci/typos from 1.40.1 to 1.41.0 ([#12997](https://github.com/foundry-rs/foundry/pull/12997)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump oven-sh/setup-bun from 2.0.2 to 2.1.0 ([#12996](https://github.com/foundry-rs/foundry/pull/12996)) by [@dependabot](https://github.com/dependabot)\[bot] * fix: `svm fails to download solc 0.8.33 on linux/arm64`, bump `svm-rs` ([#13007](https://github.com/foundry-rs/foundry/pull/13007)) by [@zerosnacks](https://github.com/zerosnacks) * chore: ignore RUSTSEC ([#13011](https://github.com/foundry-rs/foundry/pull/13011)) by [@echowandere](https://github.com/echowandere) * chore(cli): rm dead code ([#13015](https://github.com/foundry-rs/foundry/pull/13015)) by [@onbjerg](https://github.com/onbjerg) * chore(chisel): rm dead code ([#13014](https://github.com/foundry-rs/foundry/pull/13014)) by [@onbjerg](https://github.com/onbjerg) * chore(cheatcodes): rm dead code ([#13016](https://github.com/foundry-rs/foundry/pull/13016)) by [@onbjerg](https://github.com/onbjerg) * chore(common): rm dead code ([#13018](https://github.com/foundry-rs/foundry/pull/13018)) by [@onbjerg](https://github.com/onbjerg) * chore(bench): rm dead code ([#13017](https://github.com/foundry-rs/foundry/pull/13017)) by [@onbjerg](https://github.com/onbjerg) * fix: deduplicate submodule status check logic ([#13010](https://github.com/foundry-rs/foundry/pull/13010)) by [@maximevtush](https://github.com/maximevtush) * fix(forge): respect lint ignore config in solar compilation ([#12978](https://github.com/foundry-rs/foundry/pull/12978)) by [@tefyosL-sol](https://github.com/tefyosL-sol) * refactor(lint): extract duplicate help formatting logic ([#13020](https://github.com/foundry-rs/foundry/pull/13020)) by [@maximevtush](https://github.com/maximevtush) * chore(evm): deprecate RawCallResult::from\_execution\_result ([#13012](https://github.com/foundry-rs/foundry/pull/13012)) by [@ANtutov](https://github.com/ANtutov) * chore(anvil): rm dead code ([#13019](https://github.com/foundry-rs/foundry/pull/13019)) by [@onbjerg](https://github.com/onbjerg) * refactor: remove dead CheatsConfig fields and allocations ([#13031](https://github.com/foundry-rs/foundry/pull/13031)) by [@Galoretka](https://github.com/Galoretka) * chore: remove dead code ([#13030](https://github.com/foundry-rs/foundry/pull/13030)) by [@echowandere](https://github.com/echowandere) * chore(anvil): remove `anvil_getBlobSidecarsByBlockId` endpoint ([#13022](https://github.com/foundry-rs/foundry/pull/13022)) by [@mablr](https://github.com/mablr) * feat: uncomment transaction replacement test ([#13029](https://github.com/foundry-rs/foundry/pull/13029)) by [@echowandere](https://github.com/echowandere) * perf: remove redundant allocation in receipt bloom calculation ([#13035](https://github.com/foundry-rs/foundry/pull/13035)) by [@marukai67](https://github.com/marukai67) * chore: update alloy ([#12994](https://github.com/foundry-rs/foundry/pull/12994)) by [@echowandere](https://github.com/echowandere) * wallet: delegate TxSigner::address() to Signer::address() ([#12948](https://github.com/foundry-rs/foundry/pull/12948)) by [@aganisgash](https://github.com/aganisgash) * chore: bump alloy and remove RUSTSEC-2024-0437 ([#12995](https://github.com/foundry-rs/foundry/pull/12995)) by [@lean-apple](https://github.com/lean-apple) * ci: pin nightly to 2026-01-10 ([#13055](https://github.com/foundry-rs/foundry/pull/13055)) by [@mattsse](https://github.com/mattsse) * chore(deps): weekly `cargo update` ([#13044](https://github.com/foundry-rs/foundry/pull/13044)) by [@github-actions](https://github.com/github-actions)\[bot] * chore: bump evm-disassembler version to support CLZ and EOF opcodes ([#13050](https://github.com/foundry-rs/foundry/pull/13050)) by [@ckoopmann](https://github.com/ckoopmann) * chore(deps): bump `alloy-chains`, updates Tempo verifier URLs to point to Tempo's native explorer & contract verification ([#13063](https://github.com/foundry-rs/foundry/pull/13063)) by [@zerosnacks](https://github.com/zerosnacks) * chore(deps): bump mdbook to 0.5 ([#13064](https://github.com/foundry-rs/foundry/pull/13064)) by [@zerosnacks](https://github.com/zerosnacks) * feat(cheatcodes): support both 4844/7594 formats in `attachBlob` ([#13054](https://github.com/foundry-rs/foundry/pull/13054)) by [@mablr](https://github.com/mablr) * fix: wrong error message in cache write ([#13066](https://github.com/foundry-rs/foundry/pull/13066)) by [@echowandere](https://github.com/echowandere) * feat(cast): add tx flags to `erc20` command ([#13002](https://github.com/foundry-rs/foundry/pull/13002)) by [@mablr](https://github.com/mablr) * chore(deps): bump crate-ci/typos from 1.41.0 to 1.42.0 ([#13068](https://github.com/foundry-rs/foundry/pull/13068)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump taiki-e/cache-cargo-install-action from 3.0.0 to 3.0.1 ([#13070](https://github.com/foundry-rs/foundry/pull/13070)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump taiki-e/install-action from 2.65.13 to 2.66.2 ([#13069](https://github.com/foundry-rs/foundry/pull/13069)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(celo): awkward error message in transfer precompile ([#13080](https://github.com/foundry-rs/foundry/pull/13080)) by [@tefyosL-sol](https://github.com/tefyosL-sol) * fix(invariant): preserve state across calls during replay ([#13084](https://github.com/foundry-rs/foundry/pull/13084)) by [@grandizzy](https://github.com/grandizzy) * fix(evm): pin fork block number to prevent state inconsistency ([#13085](https://github.com/foundry-rs/foundry/pull/13085)) by [@grandizzy](https://github.com/grandizzy) * fix(preprocessor): mark getCode as view in VmContractHelper ([#13089](https://github.com/foundry-rs/foundry/pull/13089)) by [@grandizzy](https://github.com/grandizzy) * fix: add Tempo transaction receipt type support in TryFrom conversion ([#13047](https://github.com/foundry-rs/foundry/pull/13047)) by [@PivasDesant](https://github.com/PivasDesant) * feat(cheatcodes): add getRecordedLogsJson cheatcode ([#13093](https://github.com/foundry-rs/foundry/pull/13093)) by [@grandizzy](https://github.com/grandizzy) * feat: add Sourcify support to forge clone ([#12900](https://github.com/foundry-rs/foundry/pull/12900)) by [@avorylli](https://github.com/avorylli) * perf: add dist profile for smaller release binaries ([#13097](https://github.com/foundry-rs/foundry/pull/13097)) by [@onbjerg](https://github.com/onbjerg) * chore(deps): update figment to figment2 v0.11 ([#13099](https://github.com/foundry-rs/foundry/pull/13099)) by [@DaniPopes](https://github.com/DaniPopes) * feat: add precompile decoding for Prague BLS12-381 and Osaka P256VERIFY ([#13094](https://github.com/foundry-rs/foundry/pull/13094)) by [@DaniPopes](https://github.com/DaniPopes) * fix(anvil): use suggested priority fee by default ([#13092](https://github.com/foundry-rs/foundry/pull/13092)) by [@tefyosL-sol](https://github.com/tefyosL-sol) * chore: aggregate PRs ([#13100](https://github.com/foundry-rs/foundry/pull/13100)) by [@DaniPopes](https://github.com/DaniPopes) * chore(evm): misleading error message in traces serialization ([#13081](https://github.com/foundry-rs/foundry/pull/13081)) by [@tefyosL-sol](https://github.com/tefyosL-sol) * chore: bump vergen to v9 ([#13113](https://github.com/foundry-rs/foundry/pull/13113)) by [@zerosnacks](https://github.com/zerosnacks) * feat(cast): add eip7594 support ([#13058](https://github.com/foundry-rs/foundry/pull/13058)) by [@mablr](https://github.com/mablr) * feat(cast): add --curl flag to output equivalent curl commands ([#13114](https://github.com/foundry-rs/foundry/pull/13114)) by [@gakonst](https://github.com/gakonst) * ci: update to tempoxyz ([#13123](https://github.com/foundry-rs/foundry/pull/13123)) by [@DaniPopes](https://github.com/DaniPopes) * fix(cheatcodes): `vm.mockFunction` to work correctly with delegatecall. ([#13117](https://github.com/foundry-rs/foundry/pull/13117)) by [@quangloc99](https://github.com/quangloc99) * chore: bump v1.6.0 ([#13124](https://github.com/foundry-rs/foundry/pull/13124)) by [@gakonst](https://github.com/gakonst) * feat(fmt): Add `namespace_import_style` config ([#13108](https://github.com/foundry-rs/foundry/pull/13108)) by [@quangloc99](https://github.com/quangloc99) * chore: allow bincode unmaintained advisory ([#13129](https://github.com/foundry-rs/foundry/pull/13129)) by [@mattsse](https://github.com/mattsse) * ci: create issue on nightly `test-isolate` workflow failure ([#13132](https://github.com/foundry-rs/foundry/pull/13132)) by [@zerosnacks](https://github.com/zerosnacks) * feat(invariant): add check\_interval config for faster deep runs ([#13133](https://github.com/foundry-rs/foundry/pull/13133)) by [@grandizzy](https://github.com/grandizzy) * chore(deps): bump tempo-primitives to v1.0.0 ([#13131](https://github.com/foundry-rs/foundry/pull/13131)) by [@zerosnacks](https://github.com/zerosnacks) * feat: use Osaka as default EVM hardfork ([#13112](https://github.com/foundry-rs/foundry/pull/13112)) by [@zerosnacks](https://github.com/zerosnacks) * chore: unpin from `nightly-2026-01-10` ([#13139](https://github.com/foundry-rs/foundry/pull/13139)) by [@zerosnacks](https://github.com/zerosnacks) * chore(deps): bump to revm 34 ([#13130](https://github.com/foundry-rs/foundry/pull/13130)) by [@zerosnacks](https://github.com/zerosnacks) * fix(`forge-lint`): ignore compilation warnings in exit code ([#13138](https://github.com/foundry-rs/foundry/pull/13138)) by [@0xrusowsky](https://github.com/0xrusowsky) * chore(deps): bump taiki-e/install-action from 2.66.2 to 2.66.7 ([#13143](https://github.com/foundry-rs/foundry/pull/13143)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump crate-ci/typos from 1.42.0 to 1.42.1 ([#13144](https://github.com/foundry-rs/foundry/pull/13144)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump DeterminateSystems/update-flake-lock from 2235257b90962ba68499d64da5b0d1eaa3b46c1e to 727cc5b0b19bc265bd5ef28fc66bccb284473b5d ([#13146](https://github.com/foundry-rs/foundry/pull/13146)) by [@dependabot](https://github.com/dependabot)\[bot] * chore(deps): bump oven-sh/setup-bun from 2.1.0 to 2.1.2 ([#13145](https://github.com/foundry-rs/foundry/pull/13145)) by [@dependabot](https://github.com/dependabot)\[bot] * fix(test): skip solady testSafeMoveETHViaMover in isolation mode ([#13150](https://github.com/foundry-rs/foundry/pull/13150)) by [@gakonst](https://github.com/gakonst) * fix(script): set msg.sender from TURNKEY\_ADDRESS when using --turnkey ([#13149](https://github.com/foundry-rs/foundry/pull/13149)) by [@gakonst](https://github.com/gakonst) * fix(config): error on unknown profile with fallback for nested libs ([#13153](https://github.com/foundry-rs/foundry/pull/13153)) by [@gakonst](https://github.com/gakonst) * ci: add nightly workflow for flaky tests ([#13134](https://github.com/foundry-rs/foundry/pull/13134)) by [@zerosnacks](https://github.com/zerosnacks) * feat: warn on soldeer.lock revision mismatch during build ([#12366](https://github.com/foundry-rs/foundry/pull/12366)) by [@silvekkk](https://github.com/silvekkk) * fix(config): warn on unknown keys in all config sections ([#13154](https://github.com/foundry-rs/foundry/pull/13154)) by [@grandizzy](https://github.com/grandizzy) * fix(forge): prevent gas underflow in delete operations on Cancun ([#13157](https://github.com/foundry-rs/foundry/pull/13157)) by [@gakonst](https://github.com/gakonst) * chore: update foundry-compilers to 0.19.13 ([#13159](https://github.com/foundry-rs/foundry/pull/13159)) by [@grandizzy](https://github.com/grandizzy) * feat(fuzz): Improve call\_override to detect ETH value transfer reentrancy ([#13127](https://github.com/foundry-rs/foundry/pull/13127)) by [@grandizzy](https://github.com/grandizzy) * feat(forge script): display contract name and function in tx output ([#13156](https://github.com/foundry-rs/foundry/pull/13156)) by [@gakonst](https://github.com/gakonst) * fix(test): remove cast binary dependency from forge verify-bytecode tests ([#13161](https://github.com/foundry-rs/foundry/pull/13161)) by [@gakonst](https://github.com/gakonst) * chore(deps): bump solar 530f129 ([#13148](https://github.com/foundry-rs/foundry/pull/13148)) by [@DaniPopes](https://github.com/DaniPopes) * fix(`forge fmt`): fix incorrect indentation for chained struct calls ([#13163](https://github.com/foundry-rs/foundry/pull/13163)) by [@gakonst](https://github.com/gakonst) * fix(cli): add `--no-proxy` to disable `reqwest` proxying to prevent crash on macOS in sandboxed environments ([#13155](https://github.com/foundry-rs/foundry/pull/13155)) by [@gakonst](https://github.com/gakonst) * feat(`forge-lint`): add custom errors rule ([#13126](https://github.com/foundry-rs/foundry/pull/13126)) by [@milosdjurica](https://github.com/milosdjurica) * fix(config): preserve hyphenated profile names ([#13172](https://github.com/foundry-rs/foundry/pull/13172)) by [@gakonst](https://github.com/gakonst) * fix(verify): support chains with custom Sourcify-compatible APIs ([#13175](https://github.com/foundry-rs/foundry/pull/13175)) by [@mattsse](https://github.com/mattsse) * feat(fuzz): add address mutation variant to select from dictionary ([#13090](https://github.com/foundry-rs/foundry/pull/13090)) by [@grandizzy](https://github.com/grandizzy) * fix(verify): improve error message for CREATE2 deployment failures in verify-bytecode ([#13176](https://github.com/foundry-rs/foundry/pull/13176)) by [@grandizzy](https://github.com/grandizzy) * chore(deps): bump to foundry-compilers v0.19.4 ([#13178](https://github.com/foundry-rs/foundry/pull/13178)) by [@zerosnacks](https://github.com/zerosnacks) * fix(fmt): keep struct field access on same line after named args call ([#13166](https://github.com/foundry-rs/foundry/pull/13166)) by [@gakonst](https://github.com/gakonst) * chore: bump foundry-compilers to 0.19.14 ([#13183](https://github.com/foundry-rs/foundry/pull/13183)) by [@zerosnacks](https://github.com/zerosnacks) * feat(docker): add semver major/minor floating tags on release ([#13182](https://github.com/foundry-rs/foundry/pull/13182)) by [@zerosnacks](https://github.com/zerosnacks) ### Full Changelog: [https://github.com/foundry-rs/foundry/compare/v1.5.1...v1.6.0-rc1](https://github.com/foundry-rs/foundry/compare/v1.5.1...v1.6.0-rc1) ### Previous Releases | Version | Release Date | Release Notes | | ---------- | ------------------ | --------------------------------------------------------------------- | | v1.5.1 | December 19, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.5.1) | | v1.5.0-rc1 | November 17, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.5.0-rc1) | | v1.5.0 | November 24, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.5.0) | | v1.4.4 | October 30, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.4) | | v1.4.3 | October 22, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.3) | | v1.4.2 | October 18, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.2) | | v1.4.1 | October 14, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.1) | | v1.4.0 | October 8, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.0) | | v1.4.0-rc3 | October 6, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.0-rc3) | | v1.4.0-rc2 | October 3, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.0-rc2) | | v1.4.0-rc1 | October 1, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.4.0-rc1) | | v1.3.6 | September 16, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.6) | | v1.3.5 | September 8, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.5) | | v1.3.4 | September 3, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.4) | | v1.3.3 | August 29, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.3) | | v1.3.2 | August 21, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.2) | | v1.3.1 | August 12, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.1) | | v1.3.0-rc4 | July 30, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.0-rc4) | | v1.3.0 | July 31, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.0) | | v1.3.0-rc3 | July 29, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.0-rc3) | | v1.3.0-rc2 | July 24, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.0-rc2) | | v1.3.0-rc1 | July 17, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.3.0-rc1) | | v1.2.3 | June 8, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.2.3) | | v1.2.2 | May 30, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.2.2) | | v1.2.1-rc | May 21, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.2.1-rc) | | v1.2.1 | May 26, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.2.1) | | v1.2.0-rc1 | May 19, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.2.0-rc1) | | v1.2.0-rc | May 13, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.2.0-rc) | | v1.2.0 | May 19, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.2.0) | | v1.1.0 | April 28, 2025 | [View](https://github.com/foundry-rs/foundry/releases/tag/v1.1.0) | *** *This page is automatically updated with the latest release information from the [Foundry GitHub repository](https://github.com/foundry-rs/foundry/releases).* ### Anvil Anvil is a fast local Ethereum development node. Anvil is part of the Foundry suite and is installed alongside `forge`, `cast` and `chisel`. If you haven't installed Foundry yet, see [Foundry installation](/introduction/installation). #### Getting started To use Anvil, simply type `anvil`. To fork against a live Ethereum network run `anvil --fork-url `. Let's fork Ethereum mainnet at the latest block: ```bash anvil --fork-url https://reth-ethereum.ithaca.xyz/rpc ``` ```bash _ _ (_) | | __ _ _ __ __ __ _ | | / _` | | '_ \ \ \ / / | | | | | (_| | | | | | \ V / | | | | \__,_| |_| |_| \_/ |_| |_| 0.2.0 (c4fcf12 2024-12-12T00:23:45.094165202Z) https://github.com/foundry-rs/foundry Available Accounts ================== (0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000.000000000000000000 ETH) (1) 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (10000.000000000000000000 ETH) (2) 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC (10000.000000000000000000 ETH) (3) 0x90F79bf6EB2c4f870365E785982E1f101E93b906 (10000.000000000000000000 ETH) (4) 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 (10000.000000000000000000 ETH) (5) 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc (10000.000000000000000000 ETH) (6) 0x976EA74026E726554dB657fA54763abd0C3a0aa9 (10000.000000000000000000 ETH) (7) 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 (10000.000000000000000000 ETH) (8) 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f (10000.000000000000000000 ETH) (9) 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 (10000.000000000000000000 ETH) Private Keys ================== (0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 (1) 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d (2) 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a (3) 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6 (4) 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a (5) 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba (6) 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e (7) 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356 (8) 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97 (9) 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6 Wallet ================== Mnemonic: test test test test test test test test test test test junk Derivation path: m/44'/60'/0'/0/ Fork ================== Endpoint: https://eth.merkle.io Block number: 21387064 Block hash: 0x904aee789b82ac0412448bc2ea9bb3774d10c2dae4a0e5b7f6451ac2ecd0787a Chain ID: 1 Base Fee ================== 26049293674 Gas Limit ================== 30000000 Genesis Timestamp ================== 1734014216 Listening on 127.0.0.1:8545 ```
:::info See the [`anvil` Reference](/anvil/reference) for in depth information on Anvil and its capabilities. ::: ### Notes #### EIP-7702 and Default Accounts Since the advent of EIP-7702, Anvil's default accounts have been delegated to drainers such as [https://etherscan.io/address/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266#authlist7702](https://etherscan.io/address/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266#authlist7702) This can negatively impact developer experience when users are running Anvil in fork mode and are making RPC calls that involve one of the default anvil accounts. To avoid this issue, use a different mnemonic when starting Anvil: ```bash anvil --mnemonic "" --fork-url https://reth-ethereum.ithaca.xyz/rpc ``` ### anvil #### NAME anvil - Create a local testnet node for deploying and testing smart contracts. It can also be used to fork other EVM compatible networks. #### SYNOPSIS `anvil` \[*options*] #### DESCRIPTION Create a local testnet node for deploying and testing smart contracts. It can also be used to fork other EVM compatible networks. This section covers an extensive list of information about Mining Modes, Supported Transport Layers, Supported RPC Methods, Anvil flags and their usages. You can run multiple flags at the same time. ##### Mining Modes Mining modes refer to how frequent blocks are mined using Anvil. By default, it automatically generates a new block as soon as a transaction is submitted. You can change this setting to interval mining if you will, which means that a new block will be generated in a given period of time selected by the user. If you want to go for this type of mining, you can do it by adding the `--block-time ` flag, like in the following example. ```sh # Produces a new block every 10 seconds anvil --block-time 10 ``` There's also a third mining mode called never. In this case, it disables auto and interval mining, and mine on demand instead. You can do this by typing: ```sh # Enables never mining mode anvil --no-mining ``` To speed up the finalization of blocks, you can use the `--slots-in-an-epoch` flag with a value of `1` for example. This will lead to the block at height `N-2` being finalized, where `N` is the latest block. ##### Supported Transport Layers HTTP and Websocket connections are supported. The server listens on port 8545 by default, but it can be changed by running the following command: ```sh anvil --port ``` ##### Default CREATE2 Deployer Anvil, when used without forking, includes the [default CREATE2 deployer proxy](https://github.com/Arachnid/deterministic-deployment-proxy) at the address `0x4e59b44847b379578588920ca78fbf26c0b4956c`. This allows you to test CREATE2 deployments locally without forking. ##### Supported RPC Methods ##### Standard Methods The standard methods are based on [this](https://ethereum.org/en/developers/docs/apis/json-rpc/) reference. * `web3_clientVersion` * `web3_sha3` * `eth_chainId` * `eth_networkId` * `eth_gasPrice` * `eth_accounts` * `eth_blockNumber` * `eth_getBalance` * `eth_getStorageAt` * `eth_getBlockByHash` * `eth_getBlockByNumber` * `eth_getTransactionCount` * `eth_getBlockTransactionCountByHash` * `eth_getBlockTransactionCountByNumber` * `eth_getUncleCountByBlockHash` * `eth_getUncleCountByBlockNumber` * `eth_getCode` * `eth_sign` * `eth_signTypedData_v4` * `eth_sendTransaction` * `eth_sendRawTransaction` * `eth_call` * `eth_createAccessList` * `eth_estimateGas` * `eth_getTransactionByHash` * `eth_getTransactionByBlockHashAndIndex` * `eth_getTransactionByBlockNumberAndIndex` * `eth_getTransactionReceipt` * `eth_getUncleByBlockHashAndIndex` * `eth_getUncleByBlockNumberAndIndex` * `eth_getLogs` * `eth_newFilter` * `eth_getFilterChanges` * `eth_newBlockFilter` * `eth_newPendingTransactionFilter` * `eth_getFilterLogs` * `eth_uninstallFilter` * `eth_getWork` * `eth_subscribe` * `eth_unsubscribe` * `eth_syncing` * `eth_submitWork` * `eth_submitHashrate` * `eth_feeHistory` * `eth_getProof` * `eth_fillTransaction` * `debug_traceTransaction` Use `anvil --steps-tracing` to get `structLogs` * `debug_traceCall` Note that non-standard traces are not yet supported. This means you can't pass any arguments to the `trace` parameter. * `trace_transaction` * `trace_block` ##### Custom Methods The `anvil_*` namespace is an alias for `hardhat`. For more info, refer to the [Hardhat documentation](https://hardhat.org/hardhat-network/reference#hardhat-network-methods). `anvil_impersonateAccount` Send transactions impersonating an externally owned account or contract. `anvil_stopImpersonatingAccount` Stops impersonating an account or contract if previously set with `anvil_impersonateAccount`. `anvil_autoImpersonateAccount` Accepts `true` to enable auto impersonation of accounts, and `false` to disable it. When enabled, any transaction's sender will be automatically impersonated. Same as `anvil_impersonateAccount`. `anvil_getAutomine` Returns true if automatic mining is enabled, and false if it is not. `anvil_getBlobByHash` Returns the blob for a given a KZG commitment versioned hash. `anvil_getBlobsByTransactionHash` Returns the blobs for a given transaction hash. `anvil_getBlobsByBlockId` Returns blobs for a given block ID. Optionally filtered by a list of versioned hashes. `anvil_mine` Mines a series of blocks. `anvil_dropTransaction` Removes transactions from the pool. `anvil_reset` Reset the fork to a fresh forked state, and optionally update the fork config. `anvil_setRpcUrl` Sets the backend RPC URL. `anvil_setBalance` Modifies the balance of an account. `anvil_setCode` Sets the code of a contract. `anvil_setNonce` Sets the nonce of an address. `anvil_setStorageAt` Writes a single slot of the account's storage. `anvil_setCoinbase` Sets the coinbase address. `anvil_setLoggingEnabled` Enable or disable logging. `anvil_setMinGasPrice` Set the minimum gas price for the node. `anvil_setNextBlockBaseFeePerGas` Sets the base fee of the next block. `anvil_setChainId` Sets the chain ID of the current EVM instance. `anvil_dumpState` Returns a hex string representing the complete state of the chain. Can be re-imported into a fresh/restarted instance of Anvil to reattain the same state. `anvil_loadState` When given a hex string previously returned by `anvil_dumpState`, merges the contents into the current chain state. Will overwrite any colliding accounts/storage slots. `anvil_nodeInfo` Retrieves the configuration params for the currently running Anvil node. ##### Special Methods The special methods come from Ganache. You can take a look at the documentation [here](https://github.com/trufflesuite/ganache-cli-archive/blob/master/README.md). `evm_setAutomine` Enables or disables, based on the single boolean argument, the automatic mining of new blocks with each new transaction submitted to the network. If set to `false`, Anvil keeps mining new blocks for every block interval time set by you. If set to `true`, Anvil pauses mining new blocks, until new transactions are detected. In order to resume periodic mining from the pause, call evm\_setIntervalMining to set block interval time. `evm_setIntervalMining` Sets the mining behavior to interval with the given interval (seconds). `evm_snapshot` Snapshot the state of the blockchain at the current block. `evm_revert` Revert the state of the blockchain to a previous snapshot. Takes a single parameter, which is the snapshot id to revert to. `evm_increaseTime` Jump forward in time by the given amount of time, in seconds. `evm_setNextBlockTimestamp` Similar to `evm_increaseTime` but takes the exact timestamp that you want in the next block. `anvil_setBlockTimestampInterval` Similar to `evm_increaseTime` but sets a block timestamp `interval`. The timestamp of the next block will be computed as `lastBlock_timestamp + interval`. `evm_setBlockGasLimit` Sets the block gas limit for the following blocks. `anvil_removeBlockTimestampInterval` Removes an `anvil_setBlockTimestampInterval` if it exists. `evm_mine` Mine a single block. `anvil_enableTraces` Turn on call traces for transactions that are returned to the user when they execute a transaction (instead of just txhash/receipt). `eth_sendUnsignedTransaction` Execute a transaction regardless of signature status. For the next three methods, make sure to read [Geth's documentation](https://geth.ethereum.org/docs/rpc/ns-txpool). `txpool_status` Returns the number of transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. `txpool_inspect` Returns a summary of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. `txpool_content` Returns the details of all transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. ##### Otterscan Methods The `ots_*` namespace implements the [Otterscan specification](https://docs.otterscan.io/api-docs/ots-api). `ots_getApiLevel` Used by Otterscan to check if it's connecting to a compatible node and display a friendly message if it is not. `ots_getInternalOperations` Returns the internal ETH transfers inside a transaction. `ots_hasCode` Check if a certain address contains a deployed code. `ots_getTransactionError` Extract the transaction raw error output. `ots_traceTransaction` Extract all variations of calls, contract creation and self-destructs and returns a call tree. `ots_getBlockDetails` Tailor-made and expanded version of eth\_getBlock\* for block details page in Otterscan. `ots_getBlockTransactions` Get paginated transactions for a certain block, And removes some verbose fields such logs. `ots_searchTransactionsBefore` Gets paginated inbound/outbound transaction calls for a certain address, and before a given target block. `ots_searchTransactionsAfter` Gets paginated inbound/outbound transaction calls for a certain address, and after a given target block. `ots_getTransactionBySenderAndNonce` Gets the transaction hash for a certain sender address, given its nonce. `ots_getContractCreator` Gets the transaction hash and the address which created a contract. ##### Supported Beacon Node API endpoints In addition to the JSON-RPC API, Anvil supports some endpoints from the [Eth Beacon Node API](https://ethereum.github.io/beacon-APIs/) specification. [`GET /eth/v1/beacon/genesis`](https://ethereum.github.io/beacon-APIs/#/Beacon/getGenesis) Retrieves details of the chain's genesis. The response includes three fields: `genesis_time`, `genesis_validators_root`, and `genesis_fork_version`. However, only `genesis_time` is supported; the other two fields default to zero. [`GET /eth/v1/beacon/blobs/{block_id}[?versioned_hashes=...]`](https://ethereum.github.io/beacon-APIs/#/Beacon/getBlobs) Retrieves blobs for a given block ID. Optionally filtered by a list of versioned hashes. #### OPTIONS ##### General Options `-a, --accounts `      Set the number of accounts. \[default: 10] `--auto-impersonate`      Enable autoImpersonate on startup. `-b, --block-time `      Block time in seconds for interval mining. `--balance `      Set the balance of the accounts. \[default: 10000] `--derivation-path `      Set the derivation path of the child key to be derived. \[default: m/44'/60'/0'/0/] `-h, --help`      Print help information. `--hardfork `      Choose the EVM hardfork to use e.g. `prague`, `cancun`, `shanghai`, `paris`, `london`, etc... \[default: latest] `--init `      Initialize the genesis block with the given `genesis.json` file. `-m, --mnemonic `      BIP39 mnemonic phrase used for generating accounts. `--no-mining`      Disable auto and interval mining, and mine on demand instead. `--order `      How transactions are sorted in the mempool. \[default: fees] `-p, --port `      Port number to listen on. \[default: 8545] `--steps-tracing`      Enable steps tracing used for debug calls returning geth-style traces. \[aliases: tracing] `--ipc []`      Starts an IPC endpoint at the given `PATH` argument or the default path: unix: `tmp/anvil.ipc`, windows: `\\.\pipe\anvil.ipc`. `--silent`      Don't print anything on startup. `--timestamp `      Set the timestamp of the genesis block. `-V, --version`      Print version information. `--disable-default-create2-deployer`      Disables deploying the default CREATE2 factory when running Anvil without forking. ##### EVM Options `-f, --fork-url `      Fetch state over a remote endpoint instead of starting from an empty state. `--fork-block-number `      Fetch state from a specific block number over a remote endpoint (Must pass `--fork-url` in the same command-line). `--fork-chain-id `      Specify chain id to skip fetching it from remote endpoint. This enables offline-start mode. You still must pass both `--fork-url` and `--fork-block-number`, and already have your required state cached on disk, anything missing locally would be fetched from the remote. `--fork-retry-backoff `      Initial retry backoff on encountering errors. `--fork-transaction-hash `      Fetch state from a specific transaction hash over a remote endpoint (Must pass `--fork-url` in the same command-line). `--retries `      Number of retry requests for spurious networks (timed out requests). \[default: 5] `--timeout `      Timeout in ms for requests sent to remote JSON-RPC server in forking mode. \[default: 45000] `--compute-units-per-second `      Sets the number of assumed available compute units per second for this provider. \[default: 330] `--no-rate-limit`      Disables rate limiting for this node's provider. Will always override `--compute-units-per-second` if present. \[default: false] `--no-storage-caching`      Disables RPC caching; all storage slots are read from the endpoint. This flag overrides the project's configuration file (Must pass --fork-url in the same command-line). ##### Executor Environment Config `--base-fee ` `--block-base-fee-per-gas `      The base fee in a block. `--chain-id `      The chain ID. \[default: 31337] `--code-size-limit `      EIP-170: Contract code size limit in bytes. Useful to increase for tests. \[default: 0x6000 (\~25kb)] `--gas-limit `      The block gas limit. `--gas-price `      The gas price. ##### Server Options `--allow-origin `      Set the CORS `allow_origin`. \[default: \*] `--no-cors`      Disable CORS. `--host `      The IP address the server will listen on. `--config-out `      Writes output of `anvil` as json to user-specified file. `--prune-history`      Don't keep full chain history. `--no-request-size-limit`      Disable the request size limit. Default is 2MB #### EXAMPLES 1. Set the number of accounts to 15 and their balance to 300 ETH ```sh anvil --accounts 15 --balance 300 ``` 2. Choose the address which will execute the tests ```sh anvil --sender 0xC8479C45EE87E0B437c09d3b8FE8ED14ccDa825E ``` 3. Change how transactions are sorted in the mempool to FIFO ```sh anvil --order fifo ``` #### Shell Completions `anvil completions` *shell* Generates a shell completions script for the given shell. Supported shells are: * bash * elvish * fish * powershell * zsh ##### EXAMPLES 1. Generate shell completions script for zsh: ```sh anvil completions zsh > $HOME/.oh-my-zsh/completions/_anvil ``` #### Usage within Docker In order to run anvil as a service in Github Actions with the [Docker container](/guides/foundry-in-docker), where passing arguments to the entrypoint command is not possible, use the `ANVIL_IP_ADDR` environment variable to set the host's IP. `ANVIL_IP_ADDR=0.0.0.0` is equivalent to providing the `--host ` option. ##### Using `genesis.json` The `genesis.json` file in Anvil serves a similar purpose as in Geth, defining the network's initial state, consensus rules, and preallocated accounts to ensure all nodes start consistently and maintain network integrity. All values, including balance, gas limit and such, are to be defined as hexadecimals. * `chainId`: Identifier for the blockchain, unique to each network. * `nonce`: A counter used in hashing algorithms to ensure data integrity. * `timestamp`: The creation time of the genesis block in Unix time. * `extraData`: Additional data that can be included by the creator of the genesis block. * `gasLimit`: The maximum amount of gas that can be used in the block. * `difficulty`: A measure of how difficult it is to mine a new block. * `mixHash`: A unique identifier proving a sufficient amount of computation for the block. * `coinbase`: The Ethereum address of the miner who mined this block. * `stateRoot`: The root of the state trie, reflecting the final state after all transactions. * `alloc`: Allows pre-allocating Ether to a set of addresses with predefined balances. * `number`: The block number, with the genesis block being 0. * `gasUsed`: The total gas used in the block. * `parentHash`: The hash of the parent block, all zeros for the genesis block since there is no parent. A sample for simulating mainnet via genesis can be found [here](https://github.com/paradigmxyz/reth/blob/8f3e4a15738d8174d41f4aede5570ecead141a77/crates/primitives/res/genesis/mainnet.json). ```json { "chainId": "0x2323", "nonce": "0x42", "timestamp": "0x0", "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", "gasLimit": "0x1388", "difficulty": "0x400000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544", "alloc": { "000d836201318ec6899a67540690382780743280": { "balance": "0xad78ebc5ac6200000" } }, "number": "0x0", "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" } ``` ### Cast Cast is a Swiss Army knife for interacting with Ethereum applications from the command line. You can make smart contract calls, send transactions, or retrieve any type of chain data - all from your command-line! The `cast` binary can be used both within and outside of a Foundry project. Cast is part of the Foundry suite and is installed alongside `forge`, `chisel`, and `anvil`. If you haven't installed Foundry yet, see [Foundry installation](/introduction/installation). #### Getting started Here are a few examples of what you can do: **Check the latest block on Ethereum Mainnet**: ```sh cast block-number --rpc-url https://reth-ethereum.ithaca.xyz/rpc ``` **Check the Ether balance of `vitalik.eth`** ```sh cast balance vitalik.eth --ether --rpc-url https://reth-ethereum.ithaca.xyz/rpc ``` **Replay and trace a transaction** ```sh cast run 0x9c32042f5e997e27e67f82583839548eb19dc78c4769ad6218657c17f2a5ed31 --rpc-url https://reth-ethereum.ithaca.xyz/rpc ``` Optionally, pass `--etherscan-api-key ` to decode transaction traces using verified source maps, providing more detailed and human-readable information. **Retrieve the total supply of the DAI token** ```sh // [!include ~/snippets/output/cast/cast-call:all] ``` **Decode calldata** ```sh // [!include ~/snippets/output/cast/cast-4byte-calldata:all] ``` **Send messages between two Anvil accounts** ```sh cast send --private-key 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc $(cast from-utf8 "hello world") --rpc-url http://127.0.0.1:8545/ ```
:::info See the [`cast` Reference](/cast/reference/cast) for a complete overview of all the available subcommands. ::: ### Chisel Chisel is a fast, utilitarian, and verbose Solidity REPL. The `chisel` binary can be used both within and outside of a Foundry project. If the binary is executed in a Foundry project root, Chisel will inherit the project's configuration options. Chisel is part of the Foundry suite and is installed alongside `forge`, `cast`, and `anvil`. If you haven't installed Foundry yet, see [Foundry installation](/introduction/installation). #### Getting started To use Chisel, simply type `chisel`. ```sh chisel ``` From here, start writing Solidity code! Chisel will offer verbose feedback on each input. Create a variable `a` and query it: ```console ➜ uint256 a = 123; ➜ a Type: uint256 ├ Hex: 0x7b ├ Hex (full word): 0x000000000000000000000000000000000000000000000000000000000000007b └ Decimal: 123 ``` Finally, run `!source` to see `a` was applied: ```solidity // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.28; import {Vm} from "forge-std/Vm.sol"; contract REPL { Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); /// @notice REPL contract entry point function run() public { uint256 a = 123; } } ``` To see available commands, type `!help` within the REPL.
:::info See the [`chisel` Reference](/chisel/reference) for in depth information on Chisel and its capabilities. ::: ### chisel #### NAME `chisel` - Test and receive verbose feedback on Solidity inputs within a REPL environment. #### SYNOPSIS `chisel` \[*options*] ##### Subcommands (bin) 1. `chisel list` * Displays all cached sessions stored in `~/.foundry/cache/chisel`. 2. `chisel load ` * If a cached session with `id = ` exists, launches the REPL and loads the corresponding session. 3. `chisel view ` * If a cached session with `id = ` exists, displays the source code of the session's REPL contract. 4. `chisel clear-cache` * Deletes all cache files within the `~/.foundry/cache/chisel` directory. These sessions are unrecoverable, so use this command with care. ##### Flags See `man chisel` or `chisel --help` for all available environment configuration flags. #### DESCRIPTION Chisel is a Solidity REPL (short for "read-eval-print loop") that allows developers to write and test Solidity code snippets. It provides an interactive environment for writing and executing Solidity code, as well as a set of built-in commands for working with and debugging your code. This makes it a useful tool for quickly testing and experimenting with Solidity code without having to spin up a sandbox foundry test suite. #### Usage To open chisel, simply execute the `chisel` binary. From there, input valid Solidity code. There are two kinds of inputs to the chisel prompt apart from commands: 1. Expressions * Expressions are statements that return a value or otherwise can be evaluated on their own. For example, `1 << 8` is an expression that will evaluate to a `uint256` with the value `256`. Expressions will be evaluated up front, and will not persist in the session state past their evaluation. * Examples: * `address(0).balance` * `abi.encode(256, bytes32(0), "Chisel!")` * `myViewFunc(128)` * ... 2. Statements * Statements are snippets of code that are meant to persist in the session's state. Statements include variable definitions, calls to non-state-mutating functions that return a value, and contract, function, event, error, mapping, or struct definitions. If you would like an expression to be evaluated as a statement, a semi-colon (`;`) can be appended to the end. * Examples: * `uint256 a = 0xa57b` * `myStateMutatingFunc(128)` || `myViewFunc(128);`. Notice the `;` * ```solidity function hash64( bytes32 _a, bytes32 _b ) internal pure returns (bytes32 _hash) { assembly { // Store the 64 bytes we want to hash in scratch space mstore(0x00, _a) mstore(0x20, _b) // Hash the memory in scratch space // and assign the result to `_hash` _hash := keccak256(0x00, 0x40) } } ``` * `event ItHappened(bytes32 indexed hash)` * `struct Complex256 { uint256 re; uint256 im; }` * ... ##### Available Commands ```text // [!include ~/snippets/output/chisel/help:output] ``` **General** `!help` | `!h` Display all commands. `!quit` | `!q` Quit Chisel. `!exec [args]` | `!e [args]` Execute a shell command and print the output. Example: ```sh ➜ !e ls CHANGELOG.md LICENSE README.md TESTS.md artifacts cache contracts crytic-export deploy deploy-config deployments dist echidna.yaml forge-artifacts foundry.toml hardhat.config.ts layout-lock.json node_modules package.json scripts slither.config.json slither.db.json src tasks test-case-generator tsconfig.build.json tsconfig.build.tsbuildinfo tsconfig.json ``` **Session** `!clear` | `!c` Clear current session source. Under the hood, each Chisel session has an underlying contract that is altered as you input statements. This command clears this contract and resets your session to the default state. `!source` | `!so` Display the source code of the current session. As mentioned above, each Chisel session has an underlying contract. This command will display the source code of this contract. `!save [id]` | `!s [id]` Save the current session to cache. Chisel allows for caching sessions, which can be very useful if you are testing more complex logic in Chisel or if you want to return to a session at a later time. All cached Chisel sessions are stored in `~/.foundry/cache/chisel`. If an `id` argument is not supplied, Chisel will automatically assign a numerical ID to the session you are saving. `!load ` | `!l ` Load a previous session ID from cache. This command will load a previously cached session from the cache. Along with the session's source, all environment settings will also be loaded. The `id` argument must correspond with an existing cached session in the `~/.foundry/cache/chisel` directory. `!list` | `!ls` List all cached sessions. This command will display all cached chisel sessions within the `~/.foundry/cache/chisel` directory. `!clearcache` | `!cc` Clear the chisel cache of all stored sessions. Deletes all cache files within the `~/.foundry/cache/chisel` directory. These sessions are unrecoverable, so use this command with care. `!export` | `!ex` Export the current session source to a script file. If `chisel` was executed from the root directory of a foundry project, it is possible to export your current session to a foundry script in the `scripts` dir of your project. `!fetch ` | `!fe ` Fetch the interface of a verified contract on Etherscan. This command will attempt to parse the interface of a verified contract @ `` from the Etherscan API. If successful, the interface will be inserted into the session source with the name ``. At the moment, only interfaces of verified contracts on Ethereum mainnet can be fetched. In the future, Chisel will support fetching interfaces from multiple Etherscan-supported chains. `!edit` Open the current session's `run()` function in an editor. chisel will use the editor defined in the `$EDITOR` environment variable. **Environment** `!fork ` | `!f ` Fork an RPC for the current session. Supply 0 arguments to return to a local network. Attempts to fork the state of the provided RPC. If no URL is provided, returns to using a blank, local devnet state. `!traces` | `!t` Enable / disable traces for the current session. When tracing is enabled, foundry-style call tracing and logs will be printed after each statement is inserted. **Debug** `!memdump` | `!md` Dump the raw memory of the current state. Attempts to dump the raw memory of the machine state after the last instruction of the REPL contract's `run` function has finished executing. `!stackdump` | `!sd` Dump the raw stack of the current state. Attempts to dump the raw stack of the machine state after the last instruction of the REPL contract's `run` function has finished executing. `!rawstack ` | `!rs ` Display the raw value of a variable's stack allocation. For variables that are > 32 bytes in length, this will display their memory pointer. This command is useful when you want to view the full raw stack allocation for a variable that is less than 32 bytes in length. Example: ```sh ➜ address addr ➜ assembly { addr := not(0) } ➜ addr Type: address └ Data: 0xffffffffffffffffffffffffffffffffffffffff ➜ !rs addr Type: bytes32 └ Data: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ➜ ``` ### Continuous Integration #### GitHub Actions To test your project using GitHub Actions, here is a sample workflow: ```yml on: [push] name: test jobs: check: name: Foundry project runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: version: stable - name: Run tests run: forge test -vvv ``` #### Travis CI To test your project using Travis CI, here is a sample workflow: ```yml language: rust cache: cargo: true directories: - $HOME/.foundry install: - curl -L https://foundry.paradigm.xyz | bash - export PATH=$PATH:$HOME/.foundry/bin - foundryup -b master script: - forge test -vvv ``` ### GitLab CI To test your project using GitLab CI, here is a sample workflow: Note: check out [Policy](https://docs.gitlab.com/runner/executors/docker.html#how-pull-policies-work) to fetch the remote image ```yml variables: GIT_SUBMODULE_STRATEGY: recursive jobs: image: ghcr.io/foundry-rs/foundry script: - forge install - forge test -vvv ``` ### Dynamic Test Linking [v1.1 release](https://github.com/foundry-rs/foundry/releases/tag/v1.1.0) comes with dynamic test linking feature, built on top of [Solar](https://github.com/paradigmxyz/solar), which eliminates redundant test compilation when changing the contract logic, Foundry skips recompiling large test suites, resulting in massive time savings. How it works: On the initial build, Foundry preprocesses test contracts by extracting constructor parameters of the contracts under test and replacing direct instantiations with [`deployCode` cheatcodes](/reference/cheatcodes/get-deployed-code). Subsequent compilations reuse pre-built artifacts for deployed contracts instead of recompiling both the source and all associated test contracts. Dynamic test linking capability is built on top of [Solar](https://github.com/paradigmxyz/solar), the blazingly fast and modular Solidity compiler. You can enable this feature by setting the `dynamic_test_linking` configuration option to `true` in your `foundry.toml` file: ```toml [profile.default] ... dynamic_test_linking = true ``` OR by passing the `--dynamic-test-linking` flag to the `forge build` command: ```bash forge build --dynamic-test-linking ``` We are looking into enabling this by default in the future. Benchmarks from the [PR](https://github.com/foundry-rs/foundry/pull/10010) show greater than 10x speedup in compilation time for large projects: | Project | Change | Files compiled (with / without, after initial compile) | Time to compile (with / without, after initial compile) | | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------- | | [uniswap v4-core](https://github.com/Uniswap/v4-core/tree/80311e34080fee64b6fc6c916e9a51a437d0e482) | add `Lock.lock();` at [PoolManager.sol#L107](https://github.com/Uniswap/v4-core/blob/80311e34080fee64b6fc6c916e9a51a437d0e482/src/PoolManager.sol#L107) | 1 / 19 | 2.25s / 165.13s | | [spark-psm](https://github.com/sparkdotfi/spark-psm/tree/9d0bcc045e81407408368c9a4bb6e3f13db77e32) | change `amountOut < minAmountOut` at [PSM3.sol#L125](https://github.com/sparkdotfi/spark-psm/blob/9d0bcc045e81407408368c9a4bb6e3f13db77e32/src/PSM3.sol#L125) | 3 / 28 | 2.14s / 16.15s | | [morpho-blue-bundlers](https://github.com/morpho-org/morpho-blue-bundlers/tree/1fa17256abb86c4de48fd5e251ebd46aae70ca1a) | change `if (assets < 0)` at [MorphoBundler.sol#L106](https://github.com/morpho-org/morpho-blue-bundlers/blob/1fa17256abb86c4de48fd5e251ebd46aae70ca1a/src/MorphoBundler.sol#L106) | 11 / 36 | 16.39s / 251.05s | | [morpho-blue](https://github.com/morpho-org/morpho-blue/commit/9e2b0755b47bbe5b09bf1be8f00e060d4eab6f1c) | add `require(assets != 0, ErrorsLib.ZERO_ASSETS)` at [Morpho.sol#L424](https://github.com/morpho-org/morpho-blue/blob/9e2b0755b47bbe5b09bf1be8f00e060d4eab6f1c/src/Morpho.sol#L424) | 1 / 23 | 1.01s / 133.73s | | [sablier lockup](https://github.com/sablier-labs/lockup/tree/b2f33926fcac72a1a855c6b8ccaa75166895f13c) | change `if (cliffTime < 0)` at [SablierLockup.sol#L480](https://github.com/sablier-labs/lockup/blob/b2f33926fcac72a1a855c6b8ccaa75166895f13c/src/SablierLockup.sol#L480) | 1 / 104 | 781ms / 71.29s | | [solady](https://github.com/Vectorized/solady/commit/724c39bdfebb593157c2dfa6797c07a25dfb564c) | add additional `_setOwner(newOwner)` at [Ownable.sol#L182](https://github.com/Vectorized/solady/blob/724c39bdfebb593157c2dfa6797c07a25dfb564c/src/auth/Ownable.sol#L182) | 9 / 14 | 6.17s / 6.34s | | [euler evc](https://github.com/euler-xyz/ethereum-vault-connector/commit/64f6d2171a57e02a0f95bcbdecf1d92e9d253d40) | change `SET_MAX_ELEMENTS` to `11` at [Set.sol#L7](https://github.com/euler-xyz/ethereum-vault-connector/blob/64f6d2171a57e02a0f95bcbdecf1d92e9d253d40/src/Set.sol#L7) | 28 / 30 | 9.17s / 9.40s | ### Integrating with Hardhat It's possible to have your Foundry project work alongside [Hardhat](https://hardhat.org/). This article assumes that you have Foundry and node installed in your system. This article also assumes familiarity with both Foundry and Hardhat. #### Why does this not work out of the box? Hardhat by default expects libraries to be installed in `node_modules`, the default folder for all NodeJS dependencies. Foundry expects them to be in `lib`. Of course [we can configure Foundry](/config/overview) but not easily to the directory structure of `node_modules`. For this reason, the recommended setup is to use [hardhat-foundry](https://www.npmjs.com/package/@nomicfoundation/hardhat-foundry). When hardhat-foundry is installed and used correctly, Hardhat will use the same contracts directory that is used by Foundry, and it will be able to use dependencies installed with forge install. In this article we will cover both scenarios: 1. Adding Hardhat to a Foundry project, and, 2. Adding Foundry to a Hardhat project. #### Just show me the example repo! [Enjoy!](https://github.com/foundry-rs/HardhatInFoundry) If you want to adapt this to a Foundry project you already have or learn how it works, read below: #### Adding Hardhat to a Foundry project Inside your Foundry project working directory: 1. `npm init -y` - This will set up a `package.json` file. 2. `npm i --save-dev hardhat@2` - Install Hardhat as a dev dependency into your project. 3. `npx hardhat init` - Initialize your Hardhat project inside the same directory and choose the "**Create an empty hardhat.config.js**" option. This will create a basic `hardhat.config.js` file. 4. `npm i --save-dev @nomicfoundation/hardhat-foundry @nomicfoundation/hardhat-toolbox` - This will install the hardhat-foundry plugin and the Hardhat toolbox plugin which is a combination of all the basic dependencies you need to run Hardhat tests. Your hardhat.config.js file should look like this to make the plugins work: ```javascript require("@nomicfoundation/hardhat-toolbox"); require("@nomicfoundation/hardhat-foundry"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.19", }; ``` 5. By default, a Foundry project ships with a simple `Counter.sol` contract and a couple of tests. Create a file named `Counter.t.js` inside the `test` directory parallel to the default `Counter.t.sol` file. 6. Add the following code to the `Counter.t.js` file: ```javascript const { expect } = require("chai"); const hre = require("hardhat"); const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); describe("Counter contract", function () { async function CounterLockFixture() { const counter = await ethers.deployContract("Counter"); await counter.setNumber(0); return { counter }; } it("Should increment the number correctly", async function () { const { counter } = await loadFixture(CounterLockFixture); await counter.increment(); expect(await counter.number()).to.equal(1); }); // This is not a fuzz test because Hardhat does not support fuzzing yet. it("Should set the number correctly", async function () { const { counter } = await loadFixture(CounterLockFixture); await counter.setNumber(100); expect(await counter.number()).to.equal(100); }); }); ``` This piece of code will execute the same tests as the default `Counter.t.sol` file. And this is it! You can create Hardhat and Foundry tests in the same `test` directory and run them with `npx hardhat test` and `forge test` respectively. Check out [Hardhat's documentation](https://hardhat.org/docs) to learn more. #### Adding Foundry to a Hardhat project Inside your Hardhat project working directory: 1. `npm i --save-dev @nomicfoundation/hardhat-foundry`- Install the hardhat-foundry plugin. 2. Add `require("@nomicfoundation/hardhat-foundry");` to the top of your `hardhat.config.js` file. > ℹ️ **Note** > Step number 3 will only work if your directory is an initialized git repository. Run `git init` if you haven't already. 3. Run `npx hardhat init-foundry` in your terminal. This will generate a `foundry.toml` file based on your Hardhat project's existing configuration, and will install the `forge-std` library. Hardhat will now set up a basic Foundry project inside the same directory with a few configurations inside the `foundry.toml` file to make sure that Foundry knows where to look for your contracts, tests and dependencies. You can always change these configurations later by editing the `foundry.toml` file. ### Configuring your `foundry.toml` Forge can be configured using a configuration file called `foundry.toml`, which is placed in the root of your project. Configuration can be namespaced by profiles. The default profile is named `default`, from which all other profiles inherit. You are free to customize the `default` profile, and add as many new profiles as you need. Additionally, you can create a global `foundry.toml` in your home directory. Let's take a look at a configuration file that contains two profiles: the default profile, which always enables the optimizer, as well as a CI profile, that always displays traces: ```toml [profile.default] optimizer = true optimizer_runs = 20_000 [profile.ci] verbosity = 4 ``` When running `forge`, you can specify the profile to use using the `FOUNDRY_PROFILE` environment variable. #### Standalone sections Besides the profile sections, the configuration file can also contain standalone sections (`[fmt]`, `[fuzz]`, `[invariant]` etc). By default, each standalone section belongs to the `default` profile. i.e. `[fmt]` is equivalent to `[profile.default.fmt]`. To configure the standalone section for different profiles other than `default`, use syntax `[profile..]`. i.e. `[profile.ci.fuzz]`.
:::info See the [`foundry.toml` Reference](/config/reference/default-config) for a complete overview of what you can configure. ::: ### Shell Autocompletion You can generate autocompletion shell scripts for `bash`, `elvish`, `fish`, `nushell`, `powershell`, and `zsh`. #### zsh First, ensure that the following is present at the end in your `~/.zshrc` file (if not, add it): ```sh autoload -U compinit compinit -i ``` Then run: ```sh forge completions zsh | sudo tee /usr/local/share/zsh/site-functions/_forge cast completions zsh | sudo tee /usr/local/share/zsh/site-functions/_cast anvil completions zsh | sudo tee /usr/local/share/zsh/site-functions/_anvil ``` For macOS: ```sh forge completions zsh > /opt/homebrew/share/zsh/site-functions/_forge cast completions zsh > /opt/homebrew/share/zsh/site-functions/_cast anvil completions zsh > /opt/homebrew/share/zsh/site-functions/_anvil ``` #### fish ```sh mkdir -p $HOME/.config/fish/completions forge completions fish > $HOME/.config/fish/completions/forge.fish cast completions fish > $HOME/.config/fish/completions/cast.fish anvil completions fish > $HOME/.config/fish/completions/anvil.fish source $HOME/.config/fish/config.fish ``` #### bash ```sh mkdir -p $HOME/.local/share/bash-completion/completions forge completions bash > $HOME/.local/share/bash-completion/completions/forge cast completions bash > $HOME/.local/share/bash-completion/completions/cast anvil completions bash > $HOME/.local/share/bash-completion/completions/anvil exec bash ``` #### nushell ```sh mkdir -p $HOME/.config/nushell/completions forge completions nushell > $HOME/.config/nushell/completions/forge.nu cast completions nushell > $HOME/.config/nushell/completions/cast.nu anvil completions nushell > $HOME/.config/nushell/completions/anvil.nu ``` Then add the following to your `config.nu` file: ```nu use ~/.config/nushell/completions/forge.nu * use ~/.config/nushell/completions/cast.nu * use ~/.config/nushell/completions/anvil.nu * ``` ### Static Analyzers #### Slither To test your project using [slither](https://github.com/crytic/slither), here is a sample `slither.config.json`: ```json { "filter_paths": "lib" } ``` To run Slither on the entire project, use this command in the root of the project: ```sh slither . ``` By default (as of version 0.10.0), this will skip tests and scripts. To force inclusion of the tests and scripts, add the `--foundry-compile-all` flag. To run Slither on a single file, use this command: ```sh slither src/Contract.sol ``` Note, this requires configuring the [solc version in the foundry config file](https://book.getfoundry.sh/config/reference/solidity-compiler#solc_version). You do not need to provide remappings via the `solc_remaps` option as Slither will automatically detect remappings in a Foundry project. Slither will invoke `forge` to perform the build. See the [Slither wiki](https://github.com/crytic/slither/wiki/Usage) for more information. In order to use a custom configuration, such as the sample `slither.config.json` mentioned above, the following command is used as mentioned in the [slither-wiki](https://github.com/crytic/slither/wiki/Usage#configuration-file). By default slither looks for the `slither.config.json` but you can define the path and any other `json` file of your choice: ```sh slither --config-file /file.config.json . ``` Example output (Raw): ```bash Pragma version^0.8.13 (Counter.sol#2) necessitates a version too recent to be trusted. Consider deploying with 0.6.12/0.7.6/0.8.7 solc-0.8.13 is not recommended for deployment Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-versions-of-solidity setNumber(uint256) should be declared external: - Counter.setNumber(uint256) (Counter.sol#7-9) increment() should be declared external: - Counter.increment() (Counter.sol#11-13) Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-external Counter.sol analyzed (1 contracts with 78 detectors), 4 result(s) found ``` Slither also has a [GitHub Action](https://github.com/marketplace/actions/slither-action) for CI/CD. #### Aderyn To test your project using [aderyn](https://github.com/cyfrin/aderyn), install the [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Cyfrin.aderyn\&ssr=false#overview) supported by Cyfrin. To run the tool manually, follow the [Quick Start](https://cyfrin.gitbook.io/cyfrin-docs/aderyn-cli/quickstart) example with video guide. ```bash cd path/to/solidity/project/root aderyn ``` Explore more CLI options [here](https://cyfrin.gitbook.io/cyfrin-docs/cli-options). #### Mythril To test your project using [mythril](https://github.com/ConsenSys/mythril), here is a sample `mythril.config.json`: ```json { "remappings": ["ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/"], "optimizer": { "enabled": true, "runs": 200 } } ``` Note, you need switch `rustc` to nightly to install `mythril`: ``` rustup default nightly pip3 install mythril myth analyze src/Contract.sol --solc-json mythril.config.json ``` See the [mythril docs](https://mythril-classic.readthedocs.io/en/develop/) for more information. You can pass custom Solc compiler output to Mythril using the `--solc-json` flag. For example: ```bash myth analyze src/Counter.sol --solc-json mythril.config.json . . mythril.laser.plugin.loader [INFO]: Loading laser plugin: coverage mythril.laser.plugin.loader [INFO]: Loading laser plugin: mutation-pruner . . Achieved 11.56% coverage for code: 608060405234801561001057600080fd5b5060f78061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220659fce8aadca285da9206b61f95de294d3958c409cc3011ded856f421885867464736f6c63430008100033 mythril.laser.plugin.plugins.coverage.coverage_plugin [INFO]: Achieved 90.13% coverage for code: 6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220659fce8aadca285da9206b61f95de294d3958c409cc3011ded856f421885867464736f6c63430008100033 mythril.laser.plugin.plugins.instruction_profiler [INFO]: Total: 1.0892839431762695 s [ADD ] 0.9974 %, nr 9, total 0.0109 s, avg 0.0012 s, min 0.0011 s, max 0.0013 s . . [SWAP1 ] 1.8446 %, nr 18, total 0.0201 s, avg 0.0011 s, min 0.0010 s, max 0.0013 s [SWAP2 ] 0.8858 %, nr 9, total 0.0096 s, avg 0.0011 s, min 0.0010 s, max 0.0011 s mythril.analysis.security [INFO]: Starting analysis mythril.mythril.mythril_analyzer [INFO]: Solver statistics: Query count: 61 Solver time: 3.6820807456970215 The analysis was completed successfully. No issues were detected. ``` The findings will be listed at the end of this output if any. Since the default `Counter.sol` doesn't have any logic, `mythx` reports that no issues were found. ### Integrating with VSCode You can get Solidity support for Visual Studio Code by installing the [VSCode Solidity extension](https://github.com/juanfranblanco/vscode-solidity). To make the extension play nicely with Foundry, you may have to tweak a couple of things. #### 1. Remappings You may want to place your remappings in `remappings.txt`. If they are already in `foundry.toml`, copy them over and use `remappings.txt` instead. If you just use the autogenerated remappings that Foundry provides, run `forge remappings > remappings.txt`. #### 2. Dependencies You may have to add the following to your `.vscode/settings.json` for the extension to find your dependencies: ```json { "solidity.packageDefaultDependenciesContractsDirectory": "src", "solidity.packageDefaultDependenciesDirectory": "lib" } ``` Where `src` is the source code directory and `lib` is your dependency directory. #### 3. Formatter To enable the built-in formatter that comes with Foundry to automatically format your code on save, you can add the following settings to your `.vscode/settings.json`: ```json { "editor.formatOnSave": true, "[solidity]": { "editor.defaultFormatter": "JuanBlanco.solidity" }, "solidity.formatter": "forge" } ``` To configure the formatter settings, refer to the [Formatter](/config/reference/formatter) reference. #### 4. Solc Version Finally, it is recommended to specify a Solidity compiler version: ```json "solidity.compileUsingRemoteVersion": "v0.8.17" ``` To get Foundry in line with the chosen version, add the following to your `default` profile in `foundry.toml`. ```toml solc = "0.8.17" ``` #### Example of using OpenZeppelin contracts and non-standard project layout. ```bash . └── project └── contracts ├── lib │ ├── forge-std │ └── openzeppelin-contracts ├── script ├── src └── test ``` Add line to `remappings.txt` file ([`forge remapping`](/guides/project-setup/dependencies#remapping-dependencies)): ```solidity @openzeppelin/=lib/openzeppelin-contracts/ ``` Add line to `.vscode/settings.json` file (solidity extension settings): ```json { "solidity.remappings": [ "@openzeppelin/=project/contracts/lib/openzeppelin-contracts/" ] } ``` Now all contracts from the OpenZeppelin documentation can be used. ```javascript import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; ``` ### Vyper support Foundry supports compiling and testing Vyper contracts. #### 1. Compilation You can install Vyper by following the instructions [here](https://vyper.readthedocs.io/en/stable/installing-vyper.html). If you have `vyper` available in your PATH, foundry will automatically use it. Otherwise, you can set the path to `vyper` in your `foundry.toml` by adding the following: ```toml [vyper] path = "/path/to/vyper" ``` ##### Vyper libraries via `forge install` If you want an import like the following to work in your Vyper contract: ```vyper from snekmate.utils import eip712_domain_separator ``` You can install Vyper the desired library via `forge install` e.g. `forge install pcaversaccio/snekmate`. You then need to adjust your `foundry.toml` as follows (replacing "snekmate" with the name of your desired package): ```toml skip = ["**/lib/snekmate/**"] libs = ["lib", "lib/snekmate/src"] ``` ##### Vyper libraries via `pip` Alternatively if you want to install the package via `pip` into your system's python configuration or a virtual environment you can point foundry to it by modifying your `foundry.toml` as follows: ```toml # Assuming you have a virtual environment in `.venv` and are using Python 3.12 libs = ["lib", ".venv/lib/python3.12/site-packages/"] ``` Note that compatible alternative python package managers like `uv` will work too. #### 2. Solidity tests Let's write a test for this simple Counter contract: ```vyper number: public(uint256) @deploy @payable def __init__(initial_number: uint256): self.number = initial_number @external def set_number(new_number: uint256): self.number = new_number @external def increment(): self.number += 1 ``` We can deploy it by using the `deployCode` cheatcode from `forge-std` and test it with the following Solidity test: ```solidity import {Test} from "forge-std/Test.sol"; interface ICounter { function increment() external; function number() external view returns (uint256); function set_number(uint256 newNumber) external; } contract CounterTest is Test { ICounter public counter; uint256 initialNumber = 5; function setUp() public { counter = ICounter(deployCode("Counter", abi.encode(initialNumber))); assertEq(counter.number(), initialNumber); } function test_Increment() public { counter.increment(); assertEq(counter.number(), initialNumber + 1); } function testFuzz_SetNumber(uint256 x) public { counter.set_number(x); assertEq(counter.number(), x); } } ``` #### 3. Deploying You can deploy Vyper contracts via `forge create` command: ```bash forge create Counter --constructor-args '1' --rpc-url $RPC_URL --private-key $PRIVATE_KEY ``` And with `deployCode` you can deploy Vyper contracts in your scripts as well: ```solidity import {Script} from "forge-std/Script.sol"; contract CounterScript is Script { function run() public { vm.broadcast(); deployCode("src/Counter.vy", abi.encode(1)); } } ``` #### 4. Vyper scripts You can write Vyper scripts in the same way as Solidity scripts: ```vyper interface Vm: def startBroadcast(): nonpayable interface ICounter: def increment(): nonpayable def number() -> uint256: view vm: constant(Vm) = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) @external def run(counter: address): number_before: uint256 = staticcall ICounter(counter).number() extcall vm.startBroadcast() extcall ICounter(counter).increment() number_after: uint256 = staticcall ICounter(counter).number() assert number_after == number_before + 1 ``` Such script can be run with the following command: ```bash forge script script/Increment.s.vy --sig 'run' '' --rpc-url $RPC_URL --broadcast --private-key $PRIVATE_KEY ``` #### 5. Limitations * While you can write and run tests and scripts in Vyper, there is no `new` keyword in Vyper allowing you to deploy contracts. This will be addressed in the future with new cheatcodes. * Vyper does not allow overloads with the same names but different parameter types. Thus some cheatcode combinations might require workarounds to be used. (e.g. `startBroadcast(address sender))` and `startBroadcast(uint256 pk)`) * `forge coverage` currently does not support Vyper contracts. ### Debugger Forge ships with an interactive debugger. The debugger is accessible on [`forge test`](/forge/reference/test), on [`forge script`](/forge/reference/script) and on [`cast run`](/cast/reference/run). You can only select a single function or a single transaction to debug at the time. Using `forge test` (or `forge script`): ```sh forge test --debug --match-test "" ``` Where `` is the function signature of the file you want to debug. For example: ```sh forge test --debug --match-test "test_Increment" ``` If the matching test is a fuzz test, the debugger will open the first failing fuzz scenario, or the last successful one, whichever comes first. For example: ```sh forge test --debug --match-test "testFuzz_SetNumber" ``` Using `cast run`: ```sh cast run --debug \ 0xd15e0237413d7b824b784e1bbc3926e52f4726e5e5af30418803b8b327b4f8ca ``` #### Debugger layout ![An image of the debugger UI](/debugger.png) When the debugger is run, you are presented with a terminal divided into four quadrants: * **Quadrant 1**: The opcodes in the debugging session, with the current opcode highlighted. Additionally, the address of the current account, the program counter and the accumulated gas usage is also displayed * **Quadrant 2**: The current stack, as well as the size of the stack * **Quadrant 3**: The source view * **Quadrant 4**: The current memory of the EVM As you step through your code, you will notice that the words in the stack and memory sometimes change color. For the memory: * **Red words** are about to be written to by the current opcode * **Green words** were written to by the previous opcode * **Cyan words** are being read by the current opcode For the stack, **cyan words** are either being read or popped by the current opcode. > ⚠️ **Note** > > In most test frameworks, the first test assertion to fail is the one reported. > In foundry, the last test assertion to fail (that comes from DSTest or cheatcodes) is the one to be reported. #### Navigating #### General * q: Quit the debugger * h: Show help #### Navigating calls * 0-9 + k: Step a number of times backwards (alternatively scroll up with your mouse) * 0-9 + j: Step a number of times forwards (alternatively scroll down with your mouse) * g: Move to the beginning of the transaction * G: Move to the end of the transaction * c: Move to the previous call-type instruction (i.e. [`CALL`][op-call], [`STATICCALL`][op-staticcall], [`DELEGATECALL`][op-delegatecall], and [`CALLCODE`][op-callcode]). * C: Move to the next call-type instruction * a: Move to the previous [`JUMP`][op-jump] or [`JUMPI`][op-jumpi] instruction * s: Move to the next [`JUMPDEST`][op-jumpdest] instruction * ' + a-z: Move to `` breakpoint set by a [`vm.breakpoint`][cheat-breakpoint] cheatcode #### Navigating memory * Ctrl + j: Scroll the memory view down * Ctrl + k: Scroll the memory view up * m: Show memory as UTF8 #### Navigating the stack * J: Scroll the stack view down * K: Scroll the stack view up * t: Show labels on the stack to see what items the current op will consume [op-call]: https://www.evm.codes/#f1 [op-staticcall]: https://www.evm.codes/#fa [op-delegatecall]: https://www.evm.codes/#f4 [op-callcode]: https://www.evm.codes/#f2 [op-jumpdest]: https://www.evm.codes/#5b [op-jump]: https://www.evm.codes/#f1 [op-jumpi]: https://www.evm.codes/#57 [cheat-breakpoint]: /reference/cheatcodes/breakpoint ### Deploying Forge can deploy smart contracts to a given network with the [`forge create`](/forge/reference/create) command. Forge CLI can deploy only one contract at a time. For deploying and verifying multiple smart contracts on multiple chains in one go, Forge's [Solidity scripting](/guides/scripting-with-solidity) would be the more efficient approach. To deploy a contract, you must provide a RPC URL (env: `ETH_RPC_URL`) and the private key of the account that will deploy the contract. Additionally the `--broadcast` flag is responsible for publishing your transaction to the network as a safety precaution and mirrors the `--broadcast` flag of `forge script`. If you do not pass the `--broadcast` flag your transaction is a dry-run. To deploy `MyContract` to a network: ```sh forge create src/MyContract.sol:MyContract --rpc-url --private-key --broadcast compiling... success. Deployer: 0xa735b3c25f... Deployed to: 0x4054415432... Transaction hash: 0x6b4e0ff93a... ``` Solidity files may contain multiple contracts. `:MyContract` above specifies which contract to deploy from the `src/MyContract.sol` file. Use the `--constructor-args` flag to pass arguments to the constructor: ```solidity // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; contract MyToken is ERC20 { constructor( string memory name, string memory symbol, uint8 decimals, uint256 initialSupply ) ERC20(name, symbol, decimals) { _mint(msg.sender, initialSupply); } } ``` Additionally, we can tell Forge to verify our contract on Etherscan, Sourcify or Blockscout, if the network is supported, by passing `--verify`. ```sh forge create src/MyToken.sol:MyToken --rpc-url \ --private-key \ --broadcast \ --etherscan-api-key \ --verify \ --constructor-args "ForgeUSD" "FUSD" 18 1000000000000000000000 ``` ### Multi-chain deployments Deploying and verifying multiple smart contracts on multiple chains in one go is possible by using forking cheatcodes. For example, if you want to deploy a `Counter` contract on Sepolia Mainnet and Base Sepolia using a single command, you can configure RPC endpoints and verifiers as: ```toml [rpc_endpoints] sepolia = "${SEPOLIA_URL}" base-sepolia = "${BASE_SEPOLIA_URL}" [etherscan] sepolia = { key = "${ETHERSCAN_API_KEY}" } base-sepolia = { key = "${ETHERSCAN_API_KEY}" } ``` and create a `CounterScript` script as: ```solidity contract CounterScript is Script { function run() public { vm.createSelectFork("sepolia"); vm.startBroadcast(); new Counter(); vm.stopBroadcast(); vm.createSelectFork("base-sepolia"); vm.startBroadcast(); new Counter(); vm.stopBroadcast(); } } ``` When running: ```sh forge script script/CounterScript.s.sol --slow --multi --broadcast --private-key --verify ``` The script will create the Sepolia Mainnet fork (`vm.createSelectFork("sepolia")`), deploy and verify the `Counter` contract, and then move to Base Sepolia chain deployment (`vm.createSelectFork("base-sepolia")`). For a list of all available forking cheatcodes see [`forking`](/reference/cheatcodes/forking) docs. ### Verifying a pre-existing contract It is recommended to use the `--verify` flag with `forge create` to automatically verify the contract on explorer after a deployment. Note that for Etherscan [`ETHERSCAN_API_KEY`](https://docs.etherscan.io/getting-started/viewing-api-usage-statistics) must be set. If you are verifying an already deployed contract, read on. You can verify a contract on Etherscan, Sourcify, oklink or Blockscout with the [`forge verify-contract`](/forge/reference/verify-contract) command. You must provide: * the contract address * the contract name or the path to the contract `:` * your Etherscan API key (env: `ETHERSCAN_API_KEY`) (if verifying on Etherscan or similar explorers e.g. BscScan / BaseScan / Polygonscan). Moreover, you may need to provide: * the constructor arguments in the ABI-encoded format, if there are any * external linked libraries in `src_file_path:library_name:library_address` format, if there are any * [compiler version](https://etherscan.io/solcversions) used for build, with 8 hex digits from the commit version prefix (the commit will usually not be a nightly build). It is auto-detected if not specified. * the number of optimizations, if the Solidity optimizer was activated. It is auto-detected if not specified. * the [chain ID](https://evm-chainlist.netlify.app/), if the contract is not on Ethereum Mainnet Let's say you want to verify `MyToken` (see above). You set the [number of optimizations](/config/reference/solidity-compiler#optimizer_runs) to 1 million, compiled it with v0.8.10, and deployed it, as shown above, to the Sepolia testnet (chain ID: 11155111). Note that `--num-of-optimizations` will default to 0 if not set on verification, while it defaults to 200 if not set on deployment, so make sure you pass `--num-of-optimizations 200` if you left the default compilation settings. Here's how to verify it: ```bash forge verify-contract \ --chain-id 11155111 \ --num-of-optimizations 1000000 \ --watch \ --constructor-args $(cast abi-encode "constructor(string,string,uint256,uint256)" "ForgeUSD" "FUSD" 18 1000000000000000000000) \ --verifier etherscan \ --etherscan-api-key \ --compiler-version v0.8.10+commit.fc410830 \ \ src/MyToken.sol:MyToken Submitted contract for verification: Response: `OK` GUID: `a6yrbjp5prvakia6bqp5qdacczyfhkyi5j1r6qbds1js41ak1a` url: https://sepolia.etherscan.io//address/0x6a54…3a4c#code ``` > ℹ️ **Note:** > > External libraries can be specified with `--libraries` argument, one for each linked library. For example, to verify a contract with two linked libraries (`Maths` and `Utils`) the `forge verify-command` should be run with > > ```bash > --libraries src/lib/Maths.sol:Maths: \ > --libraries src/lib/Utils.sol:Utils: > ``` > > arguments. It is recommended to use the [`--watch`](/forge/reference/verify-contract#verify-contract-options) flag along with `verify-contract` command in order to poll for the verification result. If the `--watch` flag was not supplied, you can check the verification status with the [`forge verify-check`](/forge/reference/verify-check) command: ```bash forge verify-check --chain-id 11155111 Contract successfully verified. ```
> 💡 **Tip** > > Use Cast's [`abi-encode`](/cast/reference/abi-encode) to ABI-encode arguments. > > In this example, we ran `cast abi-encode "constructor(string,string,uint8,uint256)" "ForgeUSD" "FUSD" 18 1000000000000000000000` to ABI-encode the arguments.
#### Troubleshooting ##### `missing hex prefix ("0x") for hex string` Make sure the private key string begins with `0x`. ##### `EIP-1559 not activated` EIP-1559 is not supported or not activated on the RPC server. Pass the `--legacy` flag to use legacy transactions instead of the EIP-1559 ones. If you do development in a local environment, you can use Hardhat instead of Ganache. ##### `Failed to parse tokens` Make sure the passed arguments are of correct type. ##### `Signature error` Make sure the private key is correct. ##### `Compiler version commit for verify` If you want to check the exact commit you are running locally, try: ` ~/.svm/0.x.y/solc-0.x.y --version` where `x` and `y` are major and minor version numbers respectively. The output of this will be something like: ```bash solc, the solidity compiler commandline interface Version: 0.8.12+commit.f00d7308.Darwin.appleclang ``` Note: You cannot just paste the entire string "0.8.12+commit.f00d7308.Darwin.appleclang" as the argument for the compiler-version. But you can use the 8 hex digits of the commit to look up exactly what you should copy and paste from [compiler version](https://etherscan.io/solcversions). ##### `Invalid API Key` With [Etherscan API V2](https://docs.etherscan.io/etherscan-v2), only Etherscan keys are valid, this can be used for similar explorers eg BscScan/BaseScan/Polygonscan. Legacy keys from other explorers have been deprecated. #### Known Issues ##### Verifying Contracts With Ambiguous Import Paths Forge passes source directories (`src`, `lib`, `test` etc) as `--include-path` arguments to the compiler. This means that given the following project tree ```text |- src |-- folder |--- Contract.sol |--- IContract.sol ``` it is possible to import `IContract` inside the `Contract.sol` using `folder/IContract.sol` import path. Etherscan is not able to recompile such sources. Consider changing the imports to use relative import path. ## Linting `forge lint` is a command that analyzes Solidity source files in your project to identify potential issues, and enforce coding standards It helps maintain code quality and consistency across your codebase. ### Examples 1. Lint all Solidity files in the project: ```sh forge lint ``` 2. Lint only files in a specific directory: ```sh forge lint src/contracts/ ``` 3. Lint with only `high` and `gas` severity lints: ```sh forge lint --severity high --severity gas ``` 4. Lint with specific lint ID and output as JSON: ```sh forge lint --only-lint incorrect-shift --json ``` ### Supported Lints This section details the lints supported by `forge lint`. Each lint includes an ID, a description of the issue it checks for, its severity, and examples of incorrect and correct code. #### High Severity ##### `incorrect-shift` Warns against shift operations where the operands might be in an unconventional or potentially erroneous order, specifically when a literal is shifted by a non-literal. In Solidity, bitwise shift operations (`<<` for left shift, `>>` for right shift) take the value to be shifted as the left operand and the number of bits to shift as the right operand. This lint rule uses a heuristic to flag potentially incorrect shift oferations. To do so, it identifies expressions where literal is shifted by a variable, which can often be an indication of a logical error where the operands were intended to be reversed. If that was indeed intended, it is recommended to replace literals by constants. Alternatively, the lint rule can be disabled. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract IncorrectShift { uint64 const LARGE_NUM = 1 ether; uint256 foo = 100; function correct() public view returns (uint256) { // Shifting 'foo' by a literal '2'. return foo << 2; // Shifting a const 'LARGE_NUM' by a variable 'foo'. return LARGE_NUM << foo; } function incorrect() public view returns (uint256) { // Shifting a literal '2' by a variable 'foo'. This is likely an error. return 2 << foo; } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["incorrect-shift"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `unchecked-call` Warns when low-level calls (`.call()`, `.delegatecall()`, `.staticcall()`) do not check the success return value. Low-level calls in Solidity return a tuple `(bool success, bytes memory data)`. Not checking the `success` value can lead to silent failures where the called function reverts but execution continues, potentially resulting in unexpected behavior or security vulnerabilities. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract UncheckedCall { function correct() public { (bool success, ) = address(target).call(""); require(success, "Call failed"); // Or using if statement (bool ok, bytes memory data) = address(target).call(abi.encodeWithSignature("foo()")); if (!ok) revert("Call failed"); } function incorrect() public { // Unchecked call - success value is ignored address(target).call(""); // Unchecked call - only data is used (, bytes memory data) = address(target).call(""); } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["unchecked-call"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `erc20-unchecked-transfer` Warns when ERC20 `transfer` or `transferFrom` calls do not check the return value. While the ERC20 standard specifies that these functions should return a boolean indicating success, not all implementations follow this pattern correctly. Some tokens revert on failure, while others return false. Not checking the return value can lead to situations where a transfer fails silently, causing loss of funds or incorrect contract state. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract ERC20UncheckedTransfer { IERC20 public token; function correct() public { // Check return value with require require(token.transfer(recipient, amount), "Transfer failed"); // Or capture and check explicitly bool success = token.transferFrom(sender, recipient, amount); if (!success) revert("Transfer failed"); } function incorrect() public { // Unchecked transfer - return value ignored token.transfer(recipient, amount); // Unchecked transferFrom - return value ignored token.transferFrom(sender, recipient, amount); } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["erc20-unchecked-transfer"] ``` Note that this lint could fire false positives, as it only checks the function name, but it doesn't ensure that the called address is an ERC20 contract. Because of that, you may have to disable individual occurrences using [inline configuration](/config/reference/linter#inline-configuration). #### Medium Severity ##### divide-before-multiply Warns against performing division before multiplication within the same expression, especially with integer arithmetic. In Solidity, integer division truncates (rounds down towards zero). Performing division before multiplication can lead to a loss of precision that might be unintended and could have been avoided by reordering operations. For example, `(a / b) * c` might result in `0` if `a < b`, even if `(a * c) / b` would have yielded a non-zero result. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract DivideBeforeMultiply { function correct() public pure returns (uint256) { return (1 * 3) / 2; // Results in 1. } function incorrect() public pure returns (uint256) { return (1 / 2) * 3; // Results in 0. } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["divide-before-multiply"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `unsafe-typecast` Warns against unsafe type conversions that may result in data loss or unexpected behavior. In Solidity, typecasts are unchecked and can introduce unexpected behavior when converting between types of different sizes. For example, casting from a larger type to a smaller one (such as `uint256` to `uint8`) will silently truncate the higher-order bits. This may result in data loss and subtle, hard-to-detect bugs. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract UnsafeTypecast { function safe(uint256 largeValue) public pure { if (largeValue > type(uint8).max) revert(); // casting to 'uint8' is safe because we ensure 'largeValue' can fit above. // forge-lint: disable-next-line(unsafe-typecast) uint8 smallValue = uint8(largeValue); } function unsafe(uint256 largeValue) public pure { // This cast is unsafe: it truncates `largeValue` to fit into 8 bits, // discarding all but the lowest 8 bits (i.e., `largeValue % 256`). // Any value greater than 255 will lose data, which can lead to bugs. uint8 truncated = uint8(largeValue); } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["unsafe-typecast"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). #### Informational / Style Guide ##### `pascal-case-struct` Ensures that struct names adhere to `PascalCase` (e.g., `MyStruct`) convention. This is a common styling guideline in Solidity to improve code readability and maintain consistency. Useful resources: [Solidity Style Guide - Struct Names](https://docs.soliditylang.org/en/latest/style-guide.html#struct-names) ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract PascalCaseStruct { // Correct struct MyStruct { uint256 data; } // Incorrect struct my_struct { uint256 data; } struct myStruct { uint256 data; } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["pascal-case-struct"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `mixed-case-function` Ensures that function names adhere to `mixedCase` (e.g., `myFunction`) convention. This helps in differentiate functions from other identifiers like structs or events and is a standard practice. Useful resources: [Solidity Style Guide - Function Names](https://docs.soliditylang.org/en/latest/style-guide.html#function-names) ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract MixedCaseFunction { // Correct function myFunction() public pure returns (uint256) { return 1; } // Incorrect function MyFunction() public pure returns (uint256) { return 1; } function my_function() public pure returns (uint256) { return 1; } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["mixed-case-function"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `mixed-case-variable` Ensures that mutable variable names (local variables and state variables that are not `constant` or `immutable`) adhere to `mixedCase` (e.g., `myVariable`) convention. This aligns with the general Solidity style for variable naming. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract MixedCaseVariable { // Correct uint256 stateVariable; function correct() public { uint256 localVariable = 10; } // Incorrect uint256 state_variable; function incorrect() public { uint256 local_variable = 20; } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["mixed-case-variable"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `screaming-snake-case-const` Ensures that `constant` variable names adhere to `SCREAMING_SNAKE_CASE` (e.g., `MY_CONSTANT`). This is the standard convention for constants in Solidity, making them easily identifiable. Useful resources: [Solidity Style Guide - Constants](https://docs.soliditylang.org/en/latest/style-guide.html#constants) ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract ScreamingSnakeCaseConstant { // Correct uint256 constant MY_CONSTANT = 1; // Incorrect uint256 constant myConstant = 2; uint256 constant my_constant = 3; } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["screaming-snake-case-constant"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `screaming-snake-case-immutable` Ensures that `immutable` variable names adhere to `SCREAMING_SNAKE_CASE` (e.g., `MY_IMMUTABLE_VAR`). Similar to constants, this convention helps in distinguish immutable variables and maintaining consistency. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract ScreamingSnakeCaseImmutable { // Correct uint256 immutable MY_IMMUTABLE_VAR; // Incorrect uint256 immutable myImmutableVar; address immutable my_immutable_var; } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["screaming-snake-case-immutable"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `unused-import` Warns when imported symbols are not used anywhere in the source file. Unused imports increase deployment costs unnecessarily and reduce code clarity. This lint checks for: * Unused named imports: `import {Symbol} from "file.sol";` * Unused aliased imports: `import "file.sol" as Alias;` * Unused aliased named imports: `import {Symbol as Alias} from "file.sol";` > Note: Plain imports without aliases (`import "file.sol";`) are not checked by this lint as they might be used for their side effects. To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["unused-import"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). ##### `unaliased-plain-import` Warns when using plain imports without an alias. Plain imports like `import "file.sol";` can make it unclear where symbols are coming from and can lead to naming conflicts. Best practice is to either: * Use named imports: `import {Symbol1, Symbol2} from "file.sol";` * Use aliased imports: `import "file.sol" as FileAlias;` ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Correct - using named imports import {SafeMath, Math} from "./Math.sol"; // Correct - using aliased import import "./Utils.sol" as Utils; // Incorrect - plain import without alias import "./Helpers.sol"; ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["unaliased-plain-import"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). #### Gas Optimizations ##### `asm-keccak256` Recommends using inline assembly for `keccak256` hashing when possible. The Solidity global function `keccak256()` involves memory allocation and copying which can be less gas-efficient than a direct inline assembly implementation that operates on memory directly, especially for hashing small, fixed-size data. For production use, consider using [Vectorized's EfficientHashLib](https://github.com/Vectorized/solady/blob/main/src/utils/EfficientHashLib.sol) from the Solady library, which provides highly optimized implementations for common hashing patterns. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract HashOptimization { // Correct - inline assembly function correct(uint256 a, uint256 b) public pure returns (bytes32 hashedVal) { assembly { mstore(0x00, a) mstore(0x20, b) let hashedVal := keccak256(0x00, 0x40) } } // Alternative - using EfficientHashLib from Solady // import {EfficientHashLib} from "solady/utils/EfficientHashLib.sol"; // function efficient(uint256 a, uint256 b) public pure returns (bytes32) { // return EfficientHashLib.hash(a, b); // } // Incorrect function incorrect(uint256 a, uint256 b) public pure returns (bytes32) { return keccak256(abi.encodePacked(a, b)); } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["asm-keccak256"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). #### Codesize Optimizations ##### `unwrapped-modifier-logic` Warns when modifiers contain logic that isn't wrapped between the `_` placeholder. In Solidity, code in modifiers that appears before or after the `_` is inlined at every function using that modifier, which can significantly increase contract size when the modifier is used multiple times. Moving complex logic into internal functions that are called from the modifier can reduce bytecode size by avoiding code duplication, especially for modifiers used across many functions. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract UnwrappedModifierLogic { address owner; // Correct - Complex logic is wrapped in an internal function modifier onlyOwner() { _checkOwner(); _; } function _checkOwner(address who) internal view { require(who == owner, "Not owner"); // Additional complex checks... } // Incorrect - Logic directly in modifier gets duplicated modifier onlyOwnerIncorrect() { require(msg.sender == owner, "Not owner"); // This code is inlined at every function using this modifier _; } } ``` To disable this lint for your project, you can add its ID to the `exclude_lints` array within the `[lint]` section of the `foundry.toml` configuration file: ```toml [lint] # ... rest of lint config ... exclude_lints = ["unwrapped-modifier-logic"] ``` Alternatively, you can also disable this individual occurrence using [inline configuration](/config/reference/linter#inline-configuration). #### See Also [Lint config](/config/reference/linter) ### Forge Forge is a command-line tool that ships with Foundry. Forge tests, builds, and deploys your smart contracts. Forge is part of the Foundry suite and is installed alongside `cast`, `chisel`, and `anvil`. If you haven't installed Foundry yet, see [Foundry installation](/introduction/installation). #### Getting started The best way to understand Forge is to simply try it (in less than 30 seconds!). First, let's initialize a new `counter` example repository: ```sh forge init counter ``` Next `cd` into `counter` and build : ```sh forge build ``` ```console [⠊] Compiling... [⠔] Compiling 27 files with Solc 0.8.28 [⠒] Solc 0.8.28 finished in 452.13ms Compiler run successful! ``` Let's [test](https://book.getfoundry.sh/forge/tests#tests) our contracts: ```sh forge test ``` ```console [⠊] Compiling... No files changed, compilation skipped Ran 2 tests for test/Counter.t.sol:CounterTest [PASS] testFuzz_SetNumber(uint256) (runs: 256, μ: 31121, ~: 31277) [PASS] test_Increment() (gas: 31293) Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.35ms (4.86ms CPU time) Ran 1 test suite in 5.91ms (5.35ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests) ``` Finally, let's run our deployment script: ```sh forge script script/Counter.s.sol ``` ``` [⠊] Compiling... No files changed, compilation skipped Script ran successfully. Gas used: 109037 If you wish to simulate on-chain transactions pass a RPC URL. ``` :::info See the [`forge` Reference](/forge/reference/forge) for a complete overview of all the available subcommands. ::: ### Deterministic deployments using `CREATE2` Enshrined into the EVM as part of the [Constantinople fork](https://ethereum.org/en/history/#constantinople) of 2019, `CREATE2` is an opcode that started its journey as [EIP-1014](https://eips.ethereum.org/EIPS/eip-1014). `CREATE2` allows you to deploy smart contracts to deterministic addresses, based on parameters controlled by the deployer. As a result, it's often mentioned as enabling "counterfactual" deployments, where you can interact with an addresses that haven't been created yet because `CREATE2` guarantees known code can be placed at that address. This is in contrast to the `CREATE` opcode, where the address of the deployed contract is a function of the deployer's nonce. With `CREATE2`, you can use the same deployer account to deploy contracts to the same address across multiple networks, even if the address has varying nonces. For the best user experience it is recommended to avoid having different addresses of the same deployment across different EVM chains. :::note This guide is intended to help you get started with configuring deterministic deployments using `CREATE2`. By default, `new Counter{salt: salt}()` will use the deterministic deployer at [`0x4e59b44847b379578588920ca78fbf26c0b4956c`](https://github.com/Arachnid/deterministic-deployment-proxy). Note that the deployer may not be available on all EVM chains. A different deployer address can be configured by setting `create2_deployer` in `foundry.toml` or by using `--create2-deployer` argument. ::: Follow these steps to set up deterministic deployments: :::steps #### Configure your `foundry.toml` In order to reliably deploy to deterministic addresses we will need to make sure our bytecode stays the same. To do so configure our `foundry.toml` as follows: ```toml [profile.default] solc = "" evm_version = "" bytecode_hash = "none" cbor_metadata = false ``` #### Pin your Solc version It is required to pin your `solc` (Solidity) version. It is generally recommended to use a recent version or, if preferred, the latest version. ```toml solc = "" ``` #### Set your EVM version Next, configure your `evm_version`. It is generally recommended to use the most recent hardfork but depending on your deployment targets this may need to use an older hardfork due to opcode incompatibilities. ```toml evm_version = "" ``` #### Configure metadata and bytecode settings By default the Solidity compiler appends the hash of the metadata file at end of the bytecode. This bytecode includes things like the compiler version and the ABI. Since the source file hashes are included in the metadata file, even if a single byte of source files changes, the metadata hash changes too. That means, if we can compile a contract with given source files and the bytecode + the appended metadata hash are exactly the same as an on-chain contract, we can be sure that this is a byte-by-byte match of the same source files and the same compilation settings. The metadata file may look something like this: ```json { "compiler": { "version": "0.8.28+commit.7893614a" }, "language": "Solidity", "output": { "abi": [ { "inputs": [], "stateMutability": "nonpayable", "type": "function", "name": "increment" }, { "inputs": [], "stateMutability": "view", "type": "function", "name": "number", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ] }, { "inputs": [ { "internalType": "uint256", "name": "newNumber", "type": "uint256" } ], "stateMutability": "nonpayable", "type": "function", "name": "setNumber" } ], "devdoc": { "kind": "dev", "methods": {}, "version": 1 }, "userdoc": { "kind": "user", "methods": {}, "version": 1 } }, "settings": { "remappings": ["forge-std/=lib/forge-std/src/"], "optimizer": { "enabled": false, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "compilationTarget": { "src/Counter.sol": "Counter" }, "evmVersion": "cancun", "libraries": {} }, "sources": { "src/Counter.sol": { "keccak256": "0x09277f949d59a9521708c870dc39c2c434ad8f86a5472efda6a732ef728c0053", "urls": [ "bzz-raw://94cd5258357da018bf911aeda60ed9f5b130dce27445669ee200313cd3389200", "dweb:/ipfs/QmNbEfWAqXCtfQpk6u7TpGa8sTHXFLpUz7uebz2FVbchSC" ], "license": "UNLICENSED" } }, "version": 1 } ``` Click [here](https://playground.sourcify.dev/) to learn more about the metadata file. By disabling the metadata as follows: ```toml bytecode_hash = "none" cbor_metadata = false ``` You are not including the metadata hash as part of the bytecode. This means that whilst your bytecode can now be deterministic you won't be able to have a [`full match`](https://docs.sourcify.dev/docs/full-vs-partial-match/#full-perfect-matches), only a [`partial match`](https://docs.sourcify.dev/docs/full-vs-partial-match/#partial-matches) when verifying your contracts. Depending on your requirements this may be acceptable. #### Configure the optimizer If you are enabling the `optimizer` make sure your `optimizer_runs` stay consistent. #### Set up the CREATE2 factory By default, your contracts won't use the default (or specified using the `create2_deployer` configuration) create2 factory and will default to executing the create2 opcode from the contract it's executed on. For example, this behavior occurs when running tests or executing scripts without a private key. You can use the following configuration: ```toml always_use_create_2_factory = true ``` If you wish to always use the create2 factory. This comes handy if you wish to use the create2 factory deployment addresses in your tests for example. ::: ### Deploying the contract When using Solidity's default `CREATE` where the new address of a contract is determined by taking the `hash` of the `sender`'s address and the `sender`'s `nonce`: ``` new_contract_address = keccak256(rlp_encode([sender, nonce]))[12:] ``` ```solidity // Using the default CREATE opcode Counter counter = new Counter(); ``` Because the `nonce` can only be used a single time it on each chain it is an unreliable way of deploying to the same contract address. Instead let's use `CREATE2`'s `salt` parameter. The `salt` parameter in `CREATE2` is a key component that determines the final deployed contract address. It allows for flexibility and uniqueness in deterministic deployments. The address of the deployed contract is derived using the following formula: ``` new_contract_address = keccak256(0xff ++ deployer ++ salt ++ keccak256(init_code)) ``` ```solidity // Passing the `salt` parameter to the CREATE2 opcode Counter counter = new Counter{salt: salt}(); ``` * `0xff` is a fixed prefix ensuring uniqueness. * `deployer` is the address executing the CREATE2 operation. * `salt` is a 32-byte value chosen by the deployer. * `keccak256(bytecode)` is the hash of the contract's creation bytecode. Given that `0xff` is fixed, the `deployer` is a deterministic deployer ([0x4e59b44847b379578588920ca78fbf26c0b4956c](https://github.com/Arachnid/deterministic-deployment-proxy)) and our bytecode is fixed we can use the `salt` parameter to fully control our new contract address. ### Additional resources * [Contract Metadata](https://docs.soliditylang.org/en/latest/metadata.html) * [Deterministic deployments agnostic to the initialization code](https://github.com/Vectorized/solady/blob/main/src/utils/CREATE3.sol) ### Implementing and Testing EIP-712 signatures Foundry offers multiple utilities to make it easy and reliable to work with EIP-712 signatures. EIP-712 is a standard for hashing and signing typed structured data. Instead of signing an opaque hash, users can sign human-readable messages, significantly improving usability and security. This is particularly useful for meta-transactions, permit functions (like in ERC-20 permits), and other off-chain signature schemes. However, correctly implementing EIP-712 hashing logic can be intricate. Foundry's suite provides powerful utilities specifically designed to help developers test and validate their EIP-712 implementations with confidence. This guide will show you how to leverage Foundry's EIP-712 commands and cheatcodes with a practical, real-world example, demonstrating how to validate a complex library like Uniswap's `PermitHash.sol` from their Permit2 system. This will showcase how to ensure that a custom EIP-712 hashing implementation aligns perfectly with the standard. ### EIP-712 commands Forge offers a couple of commands which are useful when working with EIP-712 types: #### forge eip712 Outputs the canonical type definitions of the structs in the target files in the terminal. :::tip Use the `forge eip712` command to generate the canonical type definitions and manually copy-paste them into your contracts. This way you will avoid typos. ::: #### forge bind-json Automatically generates solidity bindings for the structs in the target files. The generated bindings can easily be serialized to JSON strings, and also parsed from JSON strings. Additionally, these bindings also allow the EIP-712 cheatcodes to derive the type definitions just their name. ### EIP-712 cheatcodes Foundry offers several cheatcodes to interact with EIP-712 types: ##### vm.eip712HashType * Generates the `typeHash` for an EIP-712 struct definition. This is `keccak256` of the canonical type encoding. * It can take a direct string definition (i.e. `"Mail(address from,string contents)"`) or a type name if you've used `forge bind-json` to generate bindings from your Solidity structs. ##### vm.eip712HashStruct * Computes the `structHash`: `keccak256(typeHash + encodeData(struct)).` * `encodeData(struct)` is the ABI-encoded values of the struct's members. * Like `vm.eip712HashType`, it accepts either a direct type definition string or a type name (with bindings). ##### vm.eip712HashTypedData * Generates the final EIP-712 digest to be signed: `keccak256("\x19\x01" + domainSeparator + structHash)`. * It takes a full JSON string representing the typed data as per the EIP-712 specification. Useful for end-to-end testing of signature verification. #### Testing Uniswap's `PermitHash` library Uniswap's `Permit2` system utilizes the `PermitHash.sol` library to create hashes that comply with the EIP-712 standard for various permit structures. In this guide, we will demonstrate how to use Foundry to verify that the library correctly implements the EIP-712 hashing rules. Our objective is to focus on a few hashing functions within `PermitHash.sol`. We will provide these functions with sample data and then use `vm.eip712HashStruct` —with the same data and the canonical EIP-712 type definition— to determine if the generated hashes match. #### Setting up the test environment Before starting with the validations, we have to create the `PermitHash.t.sol` test file. ```solidity // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; import "forge-std/Test.sol"; // Import the library we are testing import {PermitHash} from "src/libraries/PermitHash.sol"; import {IAllowanceTransfer as IAT} from "src/interfaces/IAllowanceTransfer.sol"; /* These are the structs, defined in `IAT`, that `PermitHash` relies on: struct PermitDetails { address token; uint160 amount; uint48 expiration; uint48 nonce; } struct PermitSingle { PermitDetails details; address spender; uint256 sigDeadline; } */ ``` > **Tip:** as previously explained, you can use `forge bind-json` to leverage Foundry's capabilities, and have higher guarantees when testing. By running that command, you can simply use the struct name when using the EIP-712 cheatcodes, and Foundry will automatically derive the canonical type definition. #### Validating `typHash` First of all, ensure that the type hashes for each of the structs are correct: ```solidity contract PermitHashTest is Test { function test_validatePermitDetails_typeHash() public { // This test doesn't rely on the bindings generated by `forge json`, therefore it requires // the string representation of the type as an input for the cheatcode. // Assume available on Uniswap's library. Otherwise you'd have to copy-paste it manually. string memory _PERMIT_DETAILS_TYPEDEF = "PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"; // The type hash constant defined in Uniswap's library bytes32 typeHash = PermitHash._PERMIT_DETAILS_TYPEHASH; // Use the cheatcode to get the expected hash (with string representation) bytes32 expected = vm.eip712HashType(_PERMIT_DETAILS_TYPEDEF); assertEq(typeHash, expected, "PermitDetails typeHash mismatch"); } function test_validatePermitSingle_typeHash() public { // The type hash constant defined in Uniswap's library bytes32 typeHash = PermitHash._PERMIT_SINGLE_TYPEHASH; // Use the cheatcode to get the expected hash (needs bindings) bytes32 expected = vm.eip712HashType("PermitSingle"); assertEq(typeHash, expected, "PermitSingle typeHash mismatch"); } } ``` :::note If the library's `typeHash` was flawed, the assertion against the cheatcode would surface it. ::: #### Validating `structHash` After being certain that the hashes of the type definitions are correct, let's validate that the hashes of the structs follow the EIP-712 specification. ```solidity contract PermitHashTest is Test { address TOKEN = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address SPENDER = 0xdEADBEeF00000000000000000000000000000000; function test_validatePermitDetails_structHash() public { // This test doesn't rely on the bindings generated by `forge bind-json`, therefore it requires // the string representation of the type as an input for the cheatcode. // Assume available on Uniswap's library. Otherwise you'd have to copy-paste it manually. string memory _PERMIT_DETAILS_TYPEDEF = "PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"; // Prepare the test data for PermitDetails IAllowanceTransfer.PermitDetails memory details = IAllowanceTransfer.PermitDetails({ token: TOKEN, amount: 100 ether, expiration: uint48(block.timestamp + 3600), nonce: 123 }); // Get the structHash from Uniswap's library. // Despite private, assume it is available with a public function. bytes32 structHash = PermitHash._hashPermitDetails(details); // Use the cheatcode to get the expected hash (with string representation) bytes32 expected = vm.eip712HashStruct(_PERMIT_DETAILS_TYPEDEF, abi.encode(details)); assertEq(structHash, expected, "PermitDetails structHash mismatch"); } function test_validatePermitSingle_structHash() public { IAT.PermitDetails memory details = IAT.PermitDetails({ token: TOKEN, amount: 200 ether, expiration: uint48(block.timestamp + 7200), nonce: 456 }); IAT.PermitSingle memory permitSingle = IAT.PermitSingle({ details: details, spender: SPENDER, sigDeadline: block.timestamp + 10800 }); // Get the structHash from Uniswap's library. bytes32 structHash = PermitHash.hash(permitSingle); // Use the cheatcode to get the expected hash (needs bindings) bytes32 expectedStructHash = vm.eip712HashStruct("PermitSingle", abi.encode(permitSingle)); assertEq(structHash, expected, "PermitSingle structHash mismatch"); } } ``` :::note If the library's `structHash` was flawed, the assertion against the cheatcode would surface it. ::: ### Forking Mainnet with `Cast` and `Anvil` By combining [Anvil][anvil] and [Cast][cast], you can fork and test by interacting with contracts on a real network. The goal of this guide is to show you how to transfer DAI tokens from someone who holds DAI to an account created by Anvil. Follow these steps to fork mainnet and transfer DAI tokens: :::steps #### Fork mainnet with Anvil Let's start by forking mainnet. ```sh anvil --fork-url https://mainnet.infura.io/v3/$INFURA_KEY ``` You will see 10 accounts are created with their public and private keys. We will work with `0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266` (Let's call this user Alice). #### Set up environment variables Go to Etherscan and search for holders of DAI tokens ([here](https://etherscan.io/token/0x6b175474e89094c44da98b954eedeac495271d0f#balances)). Let's pick a random account. In this example we will be using `0xfc2eE3bD619B7cfb2dE2C797b96DeeCbD7F68e46`. Let's export our contracts and accounts as environment variables: ```sh export ALICE=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 export DAI=0x6b175474e89094c44da98b954eedeac495271d0f export UNLUCKY_USER=0xfc2eE3bD619B7cfb2dE2C797b96DeeCbD7F68e46 ``` #### Check initial balances We can check Alice's balance using [`cast call`][cast-call]: ```sh cast call $DAI \ "balanceOf(address)(uint256)" \ $ALICE 0 ``` Similarly, we can also check our unlucky user's balance using `cast call`: ```sh cast call $DAI \ "balanceOf(address)(uint256)" \ $UNLUCKY_USER 21840114973524208109322438 ``` #### Transfer DAI tokens Let's transfer some tokens from the unlucky user to Alice using [`cast send`][cast-send]: ```sh # This calls Anvil and lets us impersonate our unlucky user cast rpc anvil_impersonateAccount $UNLUCKY_USER cast send $DAI \ --from $UNLUCKY_USER \ "transfer(address,uint256)(bool)" \ $ALICE \ 300000000000000000000000 \ --unlocked blockHash 0xbf31c45f6935a0714bb4f709b5e3850ab0cc2f8bffe895fefb653d154e0aa062 blockNumber 15052891 ... ``` #### Verify the transfer Let's check that the transfer worked: ```sh cast call $DAI \ "balanceOf(address)(uint256)" \ $ALICE 300000000000000000000000 cast call $DAI \ "balanceOf(address)(uint256)" \ $UNLUCKY_USER 21540114973524208109322438 ``` ::: [anvil]: /anvil/overview [cast]: /cast/overview [cast-call]: /cast/reference/call [cast-send]: /cast/reference/send ### Running Foundry inside of Docker This guide shows you how to build, test, and deploy a smart contract using Foundry's Docker image. It adapts code from the \[`first steps`] guide. If you haven't completed that guide yet, and are new to solidity, you may want to start with it first. Alternatively, if you have some familiarity with Docker and Solidity, you can use your own existing project and adjust accordingly. > This guide is for illustrative purposes only and provided on an as-is basis. The guide is not audited nor fully tested. No code in this guide should be used in a production environment. #### Installation and Setup The only installation required to run this guide is Docker, and optionally, an IDE of your choice. Follow the [Docker installation instructions](/introduction/installation). To keep future commands succinct, let's re-tag the image: `docker tag ghcr.io/foundry-rs/foundry:latest foundry:latest` Having Foundry installed locally is not strictly required, but it may be helpful for debugging. You can install it using [foundryup](/introduction/installation#using-foundryup). Finally, to use any of the `cast` or `forge create` portions of this guide, you will need access to an Ethereum node. If you don't have your own node running (likely), you can use a 3rd party node service. We won't recommend a specific provider in this guide. A good place to start learning about Nodes-as-a-Service is [Ethereum's article](https://ethereum.org/en/developers/docs/nodes-and-clients/nodes-as-a-service/) on the subject. **For the rest of this guide, it is assumed that the RPC endpoint of your ethereum node is set like this**: `export RPC_URL=` #### A tour around the Foundry docker image The docker image can be used in two primary ways: 1. As an interface directly to forge and cast 2. As a base image for building your own containerized test, build, and deployment tooling We will cover both, but let's start by taking a look at interfacing with foundry using docker. This is also a good test that your local installation worked! We can run any of the `cast` [commands](/cast/reference/cast) against our docker image. Let's fetch the latest block information: ```sh docker run foundry "cast block --rpc-url $RPC_URL latest" baseFeePerGas "0xb634241e3" difficulty "0x2e482bdf51572b" extraData "0x486976656f6e20686b" gasLimit "0x1c9c380" gasUsed "0x652993" hash "0x181748772da2f968bcc91940c8523bb6218a7d57669ded06648c9a9fb6839db5" logsBloom "0x406010046100001198c220108002b606400029444814008210820c04012804131847150080312500300051044208430002008029880029011520380060262400001c538d00440a885a02219d49624aa110000003094500022c003600a00258009610c410323580032000849a0408a81a0a060100022505202280c61880c80020e080244400440404520d210429a0000400010089410c8408162903609c920014028a94019088681018c909980701019201808040004100000080540610a9144d050020220c10a24c01c000002005400400022420140e18100400e10254926144c43a200cc008142080854088100128844003010020c344402386a8c011819408" miner "0x1ad91ee08f21be3de0ba2ba6918e714da6b45836" mixHash "0xb920857687476c1bcb21557c5f6196762a46038924c5f82dc66300347a1cfc01" nonce "0x1ce6929033fbba90" number "0xdd3309" parentHash "0x39c6e1aa997d18a655c6317131589fd327ae814ef84e784f5eb1ab54b9941212" receiptsRoot "0x4724f3b270dcc970f141e493d8dc46aeba6fffe57688210051580ac960fe0037" sealFields [] sha3Uncles "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" size "0x1d6bb" stateRoot "0x0d4b714990132cf0f21801e2931b78454b26aad706fc6dc16b64e04f0c14737a" timestamp "0x6246259b" totalDifficulty "0x9923da68627095fd2e7" transactions [...] uncles [] ``` If we're in a directory with some Solidity [source code](https://github.com/dmfxyz/foundry-docker-tutorial), we can mount that directory into Docker and use `forge` however we wish. For example: ```sh docker run -v $PWD:/app foundry "forge test --root /app --watch" ``` You can see our code was compiled and tested entirely within the container. Also, since we passed the `--watch` option, the container will recompile the code whenever a change is detected. #### Creating a "build and test" image Let's use the Foundry docker image as a base for using our own Docker image. We'll use the image to: 1. Build our solidity code 2. Run our solidity tests A simple `Dockerfile` can accomplish these two goals: ```docker # Use the latest foundry image FROM ghcr.io/foundry-rs/foundry # Copy our source code into the container WORKDIR /app # Build and test the source code COPY . . RUN forge build RUN forge test ``` You can build this docker image and watch forge build/run the tests within the container: ```sh docker build --no-cache --progress=plain . ``` Now, what happens if one of our tests fails? Modify `src/test/Counter.t.sol` to make a false assertion. Try to build image again. ```solidity function testFuzz_SetNumber(uint256 x) public { counter.setNumber(x); assertEq(counter.number(), 5); } ``` ```sh docker build --no-cache --progress=plain . <...> #9 0.522 Failed tests: #9 0.522 [FAIL: assertion failed: 425 != 5; counterexample: calldata=[...] args=[425]] testFuzz_SetNumber(uint256) (runs: 0, μ: 0, ~: 0) #9 0.522 #9 0.522 Suite result: FAILED. 1 passed; 1 failed; 0 skipped; finished in 686.53µs (407.06µs CPU time) ------ error: failed to solve: executor failed running [/bin/sh -c forge test]: exit code: 1 ``` Our image failed to build because our tests failed! This is actually a nice property, because it means if we have a Docker image that successfully built (and therefore is available for use), we know the code inside the image passed the tests.\* > \*Of course, chain of custody of your docker images is very important. Docker layer hashes can be very useful for verification. In a production environment, consider [signing your docker images](https://docs.docker.com/engine/security/trust/#:~\:text=To%20sign%20a%20Docker%20Image,the%20local%20Docker%20trust%20repository). #### Creating a "deployer" image Now, we'll move on to a bit more of an advanced Dockerfile. Let's add an entrypoint that allows us to deploy our code by using the built (and tested!) image. We can target the Sepolia testnet first. ```docker # Use the latest foundry image FROM ghcr.io/foundry-rs/foundry # Copy our source code into the container WORKDIR /app # Build and test the source code COPY . . RUN forge build RUN forge test # Set the entrypoint to the forge deployment command ENTRYPOINT ["forge", "create"] ``` Let's build the image, this time giving it a name: ```sh docker build --no-cache --progress=plain -t counter . ``` Here's how we can use our docker image to deploy: ```sh docker run counter-deployer --rpc-url $RPC_URL --private-key $PRIVATE_KEY ./src/Counter.sol:Counter No files changed, compilation skipped Deployer: 0x496e09fcb240c33b8fda3b4b74d81697c03b6b3d Deployed to: 0x23d465eaa80ad2e5cdb1a2345e4b54edd12560d3 Transaction hash: 0xf88c68c4a03a86b0e7ecb05cae8dea36f2896cd342a6af978cab11101c6224a9 ``` We've just built, tested, and deployed our contract entirely within a Docker container! This guide was intended for testnet, but you can run the exact same Docker image targeting mainnet and be confident that the same code is being deployed by the same tooling. #### Why is this useful? Docker is about portability, reproducibility, and environment invariance. This means you can be less concerned about unexpected changes when you switch between environments, networks, developers, etc. Here are a few basic examples of why one may like to use Docker images for smart contract deployment: * Reduces overhead of ensuring system level dependencies match between deployment environments (e.g. does your production runner always have the same version of `forge` as your dev runner?) * Increases confidence that code has been tested prior to deployment and has not been altered (e.g. if, in the above image, your code re-compiles on deployment, that's a major red flag). * Eases pain points around segregation of duties: people with your mainnet credentials do not need to ensure they have the latest compiler, codebase, etc. It's easy to ensure that the docker deploy image someone ran in testnet is identical to the one targeting mainnet. * Docker is an accepted standard on virtually all public cloud providers. It makes it easy to schedule jobs, tasks, etc that need to interact with the blockchain. #### Using `docker-compose` to launch Anvil To launch Anvil using [Docker Compose](https://docs.docker.com/compose/) one could use the following `docker-compose.yml` configuration: ```yml services: anvil: image: ghcr.io/foundry-rs/foundry container_name: anvil environment: ANVIL_IP_ADDR: "0.0.0.0" working_dir: /anvil ports: - "8545:8545" command: anvil ``` Finally, run `docker compose up`. ``` docker compose up [+] Running 1/1 ✔ Container anvil Created Attaching to anvil anvil | anvil | anvil | _ _ anvil | (_) | | anvil | __ _ _ __ __ __ _ | | anvil | / _` | | '_ \ \ \ / / | | | | anvil | | (_| | | | | | \ V / | | | | anvil | \__,_| |_| |_| \_/ |_| |_| anvil | anvil | 0.3.1-dev (fea38858b0 2025-01-21T16:48:49.865302749Z) anvil | https://github.com/foundry-rs/foundry anvil | ... ``` ### Orchestrating Scripts with Config The forge-std `Config` contract provides a powerful way to manage complex deployment scripts, especially for multi-chain environments. By centralizing configuration in TOML files, you can create maintainable, reusable scripts that adapt to different networks and deployment scenarios. ### Why Use Config for Scripts? Traditional scripting approaches often involve: * Hardcoding addresses and parameters * Dealing with ffi cheatcodes to interact with helper files * Manually tracking deployment addresses and writting back to the helper files * Complex environment variable management All these practices make deploying scripts error-prone unless developers are experienced and meticulous. The `Config` contract solves these issues by providing: * Centralized configuration in human-readable TOML files * Automatic environment variable resolution * Type-safe access to configuration values * Bidirectional updates (read and write) * Built-in multi-chain support ### Setting Up Your Configuration #### 1. Create a Configuration File Create a `deployments.toml` file in your project root: ```toml # deployments.toml # # IMPORTANT: Chain keys must be either: # - Numeric chain ID (e.g., [1], [11155111], [10]) # - Valid Alloy chain alias (e.g., [mainnet], [sepolia], [optimism]) # # See https://github.com/alloy-rs/chains for valid aliases. For new/custom chains, use numeric IDs or consider opening a PR. [mainnet] endpoint_url = "${MAINNET_RPC_URL}" [mainnet.address] # Dependencies weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" usdc = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" multisig = "${MAINNET_MULTISIG}" [mainnet.uint] min_liquidity = 1000000 # $1M minimum fee_percentage = 300 # 3% [mainnet.bool] is_testnet = false use_timelock = true [sepolia] endpoint_url = "${SEPOLIA_RPC_URL}" [sepolia.address] weth = "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9" usdc = "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8" multisig = "${SEPOLIA_MULTISIG}" [sepolia.uint] min_liquidity = 1000 # $1k for testing fee_percentage = 300 [sepolia.bool] is_testnet = true use_timelock = false ``` #### 2. Create Your Deployment Script ```solidity // script/Deploy.s.sol pragma solidity ^0.8.13; import {Script} from "forge-std/Script.sol"; import {Config} from "forge-std/Config.sol"; import {console} from "forge-std/console.sol"; // Import your contracts import {TokenFactory} from "../src/TokenFactory.sol"; import {LiquidityPool} from "../src/LiquidityPool.sol"; import {Governance} from "../src/Governance.sol"; contract DeployScript is Script, Config { // Deployment artifacts TokenFactory public factory; LiquidityPool public pool; Governance public governance; function run() public { // Load config and enable write-back for storing deployment addresses _loadConfig("./deployments.toml", true); // Get the chain we're deploying to uint256 chainId = block.chainid; console.log("Deploying to chain:", chainId); // Load configuration values address weth = config.get("weth").toAddress(); address usdc = config.get("usdc").toAddress(); address multisig = config.get("multisig").toAddress(); uint256 minLiquidity = config.get("min_liquidity").toUint256(); uint256 feePercentage = config.get("fee_percentage").toUint256(); bool useTimelock = config.get("use_timelock").toBool(); // Start broadcasting transactions vm.startBroadcast(); // Deploy contracts factory = new TokenFactory(multisig); console.log("TokenFactory deployed at:", address(factory)); pool = new LiquidityPool( weth, usdc, minLiquidity, feePercentage ); console.log("LiquidityPool deployed at:", address(pool)); if (useTimelock) { governance = new Governance(multisig, 2 days); console.log("Governance deployed with timelock at:", address(governance)); } else { governance = new Governance(multisig, 0); console.log("Governance deployed without timelock at:", address(governance)); } // Configure contracts factory.setLiquidityPool(address(pool)); pool.setFactory(address(factory)); pool.setGovernance(address(governance)); vm.stopBroadcast(); // Save deployment addresses back to config config.set("token_factory", address(factory)); config.set("liquidity_pool", address(pool)); config.set("governance", address(governance)); config.set("deployed_at", block.timestamp); config.set("deployer", msg.sender); console.log("\nDeployment complete! Addresses saved to deployments.toml"); } } ``` ### Advanced Patterns #### Multi-Chain Deployments Deploy the same contracts across multiple chains with chain-specific configurations: ```solidity contract MultiChainDeployScript is Script, Config { struct DeploymentResult { address factory; address pool; address governance; } mapping(uint256 => DeploymentResult) public deployments; function run() public { // Load config and create forks for all chains _loadConfigAndForks("./deployments.toml", true); // Deploy to each configured chain for (uint256 i = 0; i < chainIds.length; i++) { uint256 chainId = chainIds[i]; deployToChain(chainId); } // Verify cross-chain configuration verifyCrossChainSetup(); } function deployToChain(uint256 chainId) internal { // Switch to the chain's fork vm.selectFork(forkOf[chainId]); console.log("\n========================================"); console.log("Deploying to chain:", chainId); console.log("========================================"); // Config automatically uses the current fork's chain ID address weth = config.get("weth").toAddress(); bool isTestnet = config.get("is_testnet").toBool(); vm.startBroadcast(); // Deploy with chain-specific configuration TokenFactory factory = new TokenFactory( config.get("multisig").toAddress() ); LiquidityPool pool = new LiquidityPool( weth, config.get("usdc").toAddress(), config.get("min_liquidity").toUint256(), config.get("fee_percentage").toUint256() ); // Different configuration for testnets vs mainnet Governance governance; if (isTestnet) { governance = new Governance( config.get("multisig").toAddress(), 0 // No timelock on testnets ); } else { governance = new Governance( config.get("multisig").toAddress(), 2 days // Timelock on mainnet ); } vm.stopBroadcast(); // Store deployment results deployments[chainId] = DeploymentResult({ factory: address(factory), pool: address(pool), governance: address(governance) }); // Save to config file config.set("token_factory", address(factory)); config.set("liquidity_pool", address(pool)); config.set("governance", address(governance)); } function verifyCrossChainSetup() internal view { console.log("\n========================================"); console.log("Cross-chain deployment summary:"); console.log("========================================"); for (uint256 i = 0; i < chainIds.length; i++) { uint256 chainId = chainIds[i]; DeploymentResult memory result = deployments[chainId]; console.log("\nChain", chainId); console.log(" Factory:", result.factory); console.log(" Pool:", result.pool); console.log(" Governance:", result.governance); } } } ``` #### Upgrade Scripts with History Tracking Track deployment history and manage upgrades: ```solidity contract UpgradeScript is Script, Config { function run() public { _loadConfig("./deployments.toml", true); // Read current deployment address currentImpl = config.get("implementation_v1").toAddress(); address proxy = config.get("proxy").toAddress(); console.log("Current implementation:", currentImpl); console.log("Proxy address:", proxy); vm.startBroadcast(); // Deploy new implementation MyContractV2 newImpl = new MyContractV2(); // Upgrade proxy IProxy(proxy).upgradeTo(address(newImpl)); vm.stopBroadcast(); // Archive old implementation and save new one config.set("implementation_v1_deprecated", currentImpl); config.set("implementation_v2", address(newImpl)); config.set("upgraded_at", block.timestamp); config.set("upgraded_by", msg.sender); console.log("Upgrade complete!"); console.log("New implementation:", address(newImpl)); } } ``` ### Best Practices #### 1. Chain Configuration When configuring chains in your TOML files: **Use numeric chain IDs for maximum compatibility:** ```toml [1] endpoint_url = "${MAINNET_RPC}" [1234] endpoint_url = "${CUSTOM_CHAIN_RPC}" ``` **Use Alloy aliases only for battle-tested chains:** ```toml [mainnet] [optimism] [arbitrum-sepolia] [base-sepolia] ``` **Check Alloy chains before using aliases:** * Visit [Alloy chains repository](https://github.com/alloy-rs/chains/blob/main/src/named.rs) * Search for your chain's alias. If not found, use the numeric chain ID or consider opening a PR. #### 2. Environment Variables Store sensitive data in environment variables: ```bash # .env MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY MAINNET_MULTISIG=0x742d35Cc6634C0532925a3b844Bc9e7595f0fA9b SEPOLIA_MULTISIG=0x1234567890123456789012345678901234567890 PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` #### 3. Configuration Validation Validate configuration before deployment: ```solidity function validateConfig() internal view { // Ensure critical addresses are set require( config.get("multisig").toAddress() != address(0), "Multisig not configured" ); // Validate parameters are within expected ranges uint256 fee = config.get("fee_percentage").toUint256(); require(fee <= 1000, "Fee too high"); // Max 10% // Check chain-specific requirements if (!config.get("is_testnet").toBool()) { require(config.get("use_timelock").toBool(), "Timelock required for mainnet"); } } ``` #### 4. Separate Config Files Use different config files for different purposes: ````solidity // Development deployments _loadConfig("./config/dev.toml", true); // Production deployments _loadConfig("./config/prod.toml", true); // Testing configuration _loadConfig("./config/test.toml", false); ## Running Your Scripts Execute your configuration-driven scripts: ```bash # Dry run (simulation) forge script script/Deploy.s.sol:DeployScript \ --rpc-url $SEPOLIA_RPC_URL # Deploy to testnet forge script script/Deploy.s.sol:DeployScript \ --rpc-url $SEPOLIA_RPC_URL \ --private-key $PRIVATE_KEY \ --broadcast \ --verify # Deploy to multiple chains forge script script/MultiChainDeploy.s.sol:MultiChainDeployScript \ --broadcast \ --verify ```` ### Troubleshooting #### Common Issues 1. **Environment variables not resolved**: Ensure variables are exported in your shell or defined in `.env` 2. **File permissions**: Grant file system access in `foundry.toml`: ```toml fs_permissions = [{ access = "read-write", path = "./" }] ``` 3. **`InvalidChainKey` error**: This occurs when using a custom chain name that doesn't match an Alloy chain alias. **Problem:** ```toml [my_custom_chain] # This will fail! endpoint_url = "..." ``` **Solutions:** * Use the numeric chain ID: ```toml [1234] # Works for any chain endpoint_url = "..." ``` * Or use an exact Alloy chain alias (see [supported chains](https://github.com/alloy-rs/chains/blob/main/src/named.rs)): ```toml [arbitrum-sepolia] # Works for supported chains endpoint_url = "..." ``` 4. **Type mismatch errors**: Verify that values in TOML match their declared types (e.g., addresses must be valid hex strings) ### See Also * [Config Reference](/reference/forge-std/config.mdx) * [StdConfig Reference](/reference/forge-std/std-config.mdx) * [Scripting with Solidity](/guides/scripting-with-solidity) * [Best Practices for Writing Scripts](/guides/best-practices/writing-scripts) ### Scripting with Solidity Solidity scripting is a way to declaratively deploy contracts using Solidity, instead of using the more limiting and less user friendly [`forge create`](/forge/reference/create). Solidity scripts are like the scripts you write when working with tools like Hardhat; what makes Solidity scripting different is that they are written in Solidity instead of JavaScript, and they are run on the fast Foundry EVM backend, which provides advanced simulation with dry-run capabilities. ### How `forge script` works? `forge script` does not work in an asynchronous manner. First, it collects all transactions from the script, and only then does it broadcast them all. It can essentially be split into 4 phases: 1. Local Simulation - The contract script is run in a local evm. If a rpc/fork url has been provided, it will execute the script in that context. Any **external call** (not static, not internal) from a `vm.broadcast` and/or `vm.startBroadcast` will be appended to a list. 2. Onchain Simulation - Optional. If a rpc/fork url has been provided, then it will sequentially execute all the collected transactions from the previous phase here. 3. Broadcasting - Optional. If the `--broadcast` flag is provided and the previous phases have succeeded, it will broadcast the transactions collected at step `1`. and simulated at step `2`. 4. Verification - Optional. If the `--verify` flag is provided, there's an API key, and the previous phases have succeeded it will attempt to verify the contract. (eg. etherscan). :::tip Transactions that previously failed or timed-out can be submitted again by providing `--resume` flag. ::: Given this flow, it's important to be aware that transactions whose behaviour can be influenced by external state/actors might have a different result than what was simulated on step `2`, e.g. front running. ### Setup `Counter` Project Let's try to deploy the basic `Counter` contract Foundry provides: ```sh forge init Counter ``` Next compile our contracts to make sure everything is in order. ```sh forge build ``` ### Deploying the `Counter` contract ::::steps #### Get RPC and Etherscan API Keys We are going to deploy the `Counter` contract to the Sepolia testnet but in order to do so we will need to complete a few prerequisites: 1. Get a Sepolia RPC URL. You can either grab an RPC URL from [Chainlist](https://chainlist.org/chain/11155111) or use an RPC provider like [Alchemy](https://www.alchemy.com/) or [Infura](https://www.infura.io/). 2. Get a one-time use private key for deploying. ```sh `cast wallet new` ``` ``` Successfully created new keypair. Address: Private key: ``` 3. Fund the private key. Grab some Sepolia testnet ETH, available in different faucets: * [Proof of work faucet](https://sepolia-faucet.pk910.de/) * [Alchemy](https://sepoliafaucet.com/) * [Quicknode](https://faucet.quicknode.com/ethereum/sepolia) * [Chainstack](https://faucet.chainstack.com/) Some faucets require you to have a balance on Ethereum mainnet. If so, claim the testnet ETH on a wallet you control and transfer the testnet ETH to your newly created deployer keypair. 4. Get a Sepolia Etherscan API key [here](https://docs.etherscan.io/getting-started/viewing-api-usage-statistics). #### Configuring `foundry.toml` Once you have all that create a `.env` file and add the variables. Foundry automatically loads in a `.env` file present in your project directory. The .env file should follow this format: ```sh SEPOLIA_RPC_URL= ETHERSCAN_API_KEY= ``` We now need to edit the `foundry.toml` file. There should already be one in the root of the project. Add the following lines to the end of the file: ```toml [rpc_endpoints] sepolia = "${SEPOLIA_RPC_URL}" [etherscan] sepolia = { key = "${ETHERSCAN_API_KEY}" } ``` This creates a [RPC alias](/reference/cheatcodes/rpc) for Sepolia and loads the Etherscan API key. However this does not affect the `getChain` method. #### Writing the script Next, navigate to the `script` folder and locate the `CounterScript`. :::tip For complex deployments, especially multi-chain scenarios, consider using the [Config contract for orchestrating scripts](/guides/scripting-with-config). It provides centralized configuration management through TOML files, making your scripts more maintainable and reusable, as well as built-in support for instantiating and tracking forks. ::: Modify the contents so it looks like this: ```solidity // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {Script, console} from "forge-std/Script.sol"; import {Counter} from "../src/Counter.sol"; contract CounterScript is Script { Counter public counter; function setUp() public {} function run() public { vm.startBroadcast(); counter = new Counter(); vm.stopBroadcast(); } } ``` Now let's read through the code and figure out what it actually means and does. ```solidity // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; ``` Remember even if it's a script it still works like a smart contract, but is never deployed, so just like any other smart contract written in Solidity the `pragma version` has to be specified. ```solidity import {Script, console} from "forge-std/Script.sol"; import {Counter} from "../src/Counter.sol"; ``` Just like we may import Forge Std to get testing utilities when writing tests, it also provides some scripting utilities. The next line just imports the `Counter` contract. ```solidity contract CounterScript is Script { ``` We have created a contract called `CounterScript` and it inherits `Script` from Forge Std. ```solidity function run() external { ``` By default, scripts are executed by calling the function named `run`, our entrypoint. This loads in the private key from our `.env` file. **Note:** you must be careful when exposing private keys in a `.env` file and loading them into programs. This is only recommended for use with non-privileged deployers or for local / test setups. For production setups please review the various [wallet options](/forge/reference/script#wallet-options---raw) that Foundry supports. ```solidity vm.startBroadcast(); ``` This is a special cheatcode that records calls and contract creations made by our main script contract. The private key of the sender we will pass in will instruct it to use that key for signing the transactions. Later, we will broadcast these transactions to deploy our `Counter` contract. ```solidity Counter counter = new Counter(); ``` Here we have just created our `Counter` contract. Because we called `vm.startBroadcast()` before this line, the contract creation will be recorded by Forge, and as mentioned previously, we can broadcast the transaction to deploy the contract on-chain. The broadcast transaction logs will be stored in the `broadcast` directory by default. You can change the logs location by setting [`broadcast`](/config/reference/project#broadcast) in your `foundry.toml` file. The broadcasting sender is determined by checking the following in order: 1. If `--sender` argument was provided, that address is used. 2. If exactly one signer (e.g. private key, hardware wallet, keystore) is set, that signer is used. 3. Otherwise, the default Foundry sender (`0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38`) is attempted to be used. Now that you're up to speed about what the script smart contract does, let's run it. #### Deploying to a testnet You should have added the variables we mentioned earlier to the `.env` for this next part to work. At the root of the project run: ```sh # To load the variables in the .env file source .env # To deploy and verify our contract forge script --chain sepolia script/Counter.s.sol:CounterScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv --interactives 1 ``` Note the `--interactives 1`, this will open an interactive prompt to enter your private key. For anything beyond a simple testnet deployment in a development setting you are **STRONGLY** [recommended to use a hardware wallet or a password protected keystore](/guides/best-practices/key-management). ``` Enter private key: ``` Forge is going to run our script and broadcast the transactions for us - this can take a little while, since Forge will also wait for the transaction receipts. You should see something like this after a minute or so: ``` [⠊] Compiling... No files changed, compilation skipped Enter private key: Traces: [137029] CounterScript::run() ├─ [0] VM::startBroadcast() │ └─ ← [Return] ├─ [96345] → new Counter@
│ └─ ← [Return] 481 bytes of code ├─ [0] VM::stopBroadcast() │ └─ ← [Return] └─ ← [Stop] Script ran successfully. ## Setting up 1 EVM. ========================== Simulated On-chain Traces: [96345] → new Counter@
└─ ← [Return] 481 bytes of code ========================== Chain 11155111 Estimated gas price: gwei Estimated total gas used for script: Estimated amount required: ETH ========================== ##### sepolia ✅ [Success] Hash: Contract Address:
Block: Paid: ✅ Sequence #1 on sepolia | Total Paid: ========================== ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. ## Start verification for (1) contracts Start verifying contract `
` deployed on sepolia Compiler version: 0.8.28 Submitting verification for [src/Counter.sol:Counter]
. Submitted contract for verification: Response: `OK` GUID: `` URL: https://sepolia.etherscan.io/address/
Contract verification status: Response: `NOTOK` Details: `Pending in queue` Warning: Verification is still pending...; waiting 15 seconds before trying again (7 tries remaining) Contract verification status: Response: `OK` Details: `Pass - Verified` Contract successfully verified All (1) contracts were verified! Transactions saved to: /home/user/counter/broadcast/Counter.s.sol/11155111/run-latest.json Sensitive values saved to: /home/user/counter/cache/Counter.s.sol/11155111/run-latest.json ``` This confirms that you have successfully deployed the `Counter` contract to the Sepolia testnet and have also verified it on Etherscan, all with one command. #### Deploying to a local Anvil instance You can deploy to Anvil, the local testnet, by configuring the `--fork-url`. Let's start Anvil in one terminal window: ```sh anvil ``` This will show you are list of default accounts. ``` Available Accounts ================== (0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000.000000000000000000 ETH) ... Private Keys ================== (0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ... ``` Then run the following script in a different terminal window: ```sh forge script script/Counter.s.sol:CounterScript --fork-url http://localhost:8545 --broadcast --interactives 1 ``` Next enter the private key, pick one from the list. ``` Enter private key: ``` ``` [⠊] Compiling... No files changed, compilation skipped Enter private key: Script ran successfully. ## Setting up 1 EVM. ========================== Chain 31337 Estimated gas price: 2.000000001 gwei Estimated total gas used for script: 203856 Estimated amount required: 0.000407712000203856 ETH ========================== ##### anvil-hardhat ✅ [Success] Hash: 0x6795deaad7fd483eda4b16af7d8b871c7f6e49beb50709ce1cf0ca81c29247d1 Contract Address: 0x5FbDB2315678afecb367f032d93F642f64180aa3 Block: 1 Paid: 0.000156813000156813 ETH (156813 gas * 1.000000001 gwei) ✅ Sequence #1 on anvil-hardhat | Total Paid: 0.000156813000156813 ETH (156813 gas * avg 1.000000001 gwei) ========================== ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. Transactions saved to: /home/user/counter/broadcast/Counter.s.sol/31337/run-latest.json Sensitive values saved to: /home/user/counter/cache/Counter.s.sol/31337/run-latest.json ``` :::: ### Foundry Tutorial Videos Unofficial *youtube playlists* of Foundry tutorials from Blockchain educators. | URL | Description | Author | | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------: | | | *Blockchain Developer, Solidity, Foundry Full Course 2023* \~ Learn Solidity, Blockchain Development, & Smart Contracts Powered By AI - Full Course | Patrick Collins | | | *Foundry* \~ Playlist of beginner level videos on Foundry | Smart Contract Programmer | | | A Complete Introduction to Smart Contract Development With Foundry | Axelar | | | Cyfrin Updraft - Foundry Fundamentals | Cyfrin Updraft | | | Cyfrin Updraft - Advanced Foundry | Cyfrin Updraft | ### Getting Started Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. It consists of four essential tools that suffice all the needs a blockchain app developer will ever have. Here's an overview of the tools available at your disposal after [running foundryup](/introduction/installation#using-foundryup): | Tool | What it enables | | -------------------------------- | ------------------------------------------------------------------- | | **[`forge`](/forge/overview)** | Build, test, debug, deploy and verify smart contracts | | **[`anvil`](/anvil/overview)** | Run a local Ethereum development node with forking capabilities | | **[`cast`](/cast/overview)** | Interact with contracts, send transactions, and retrieve chain data | | **[`chisel`](/chisel/overview)** | Fast Solidity REPL for rapid prototyping and debugging | :::tip You can always view detailed help for any command or subcommand by appending `--help` to it. ::: *** #### Forge Forge is a command-line tool for building, testing, and deploying smart contracts. ##### Initialize a new project ```bash # Create a new project called Counter forge init Counter cd Counter ``` ##### Build and test contracts ```bash # Compile your contracts forge build # Run your test suite forge test # Run tests against live chain state by forking forge test --fork-url https://reth-ethereum.ithaca.xyz/rpc ``` ##### Deploy contracts ```bash # Use forge scripts to deploy contracts # Set your private key export PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" # Deploy to local anvil instance forge script script/Counter.s.sol --rpc-url http://127.0.0.1:8545 --broadcast --private-key $PRIVATE_KEY ``` `forge` also enables more advanced workflows such as: * [Table testing](/forge/advanced-testing/table-testing) - Property-based testing with test cases inputs organized into a table format * [Fuzz testing](/forge/advanced-testing/fuzz-testing) - Property-based testing with randomized inputs * [Invariant testing](/forge/advanced-testing/invariant-testing) - Test system-wide properties across function call sequences * [Gas tracking](/forge/gas-tracking/overview) - Monitor and optimize gas consumption across your contracts * [Coverage reports](/forge/reference/coverage) - Generate detailed test coverage analysis with `forge coverage` Learn more about `forge` [here](/forge/overview). *** #### Anvil Anvil is a fast local Ethereum development node that is perfect for testing your contracts and other blockchain workflows in a controlled environment. ##### Start a local development node ```bash # Start anvil with 10 pre-funded accounts anvil ``` ##### Fork mainnet state ```bash # Fork latest mainnet state for testing anvil --fork-url https://reth-ethereum.ithaca.xyz/rpc ``` `anvil` comes up with other advanced capabilities such as: * **Custom `anvil_` methods** - Advanced node control including [account impersonation](/anvil/reference#anvil_impersonateaccount), [state manipulation](/anvil/reference#anvil_setbalance), and [mining control](/anvil/reference#anvil_mine) * **Forking capabilities** - Fork anvil off another live chain All of the above is provided while maintaining full compliance with the Ethereum JSON-RPC spec. Learn more about `anvil` [here](/anvil/overview). #### Cast Cast is your Swiss army knife for interacting with Ethereum applications from the command line. You can make smart contract calls, send transactions, or retrieve any type of chain data. ##### Read contract data ```bash # Check ETH balance cast balance vitalik.eth --ether --rpc-url https://reth-ethereum.ithaca.xyz/rpc # Call a contract function to read data cast call 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \ "balanceOf(address)" 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \ --rpc-url https://reth-ethereum.ithaca.xyz/rpc ``` ##### Send transactions ```bash # Set your private key export PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" # Send ETH to an address cast send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 --value 10000000 --private-key $PRIVATE_KEY ``` ##### Interact with JSON-RPC ```bash # Call JSON-RPC methods directly cast rpc eth_getHeaderByNumber $(cast 2h 22539851) --rpc-url https://reth-ethereum.ithaca.xyz/rpc # Get latest block number cast block-number --rpc-url https://reth-ethereum.ithaca.xyz/rpc ``` Learn more about `cast` [here](/cast/overview). *** #### Chisel Chisel is a fast, utilitarian, and verbose Solidity REPL for rapid prototyping and debugging. It's perfect for testing Solidity snippets and exploring contract behavior interactively. ##### Start the REPL ```bash # Launch chisel REPL chisel ``` ##### Interactive Solidity development ```solidity // Create and query variables ➜ uint256 a = 123; ➜ a Type: uint256 ├ Hex: 0x7b ├ Hex (full word): 0x000000000000000000000000000000000000000000000000000000000000007b └ Decimal: 123 // Test contract functions ➜ function add(uint256 x, uint256 y) public pure returns (uint256) { return x + y; } ➜ add(5, 10) Type: uint256 └ Decimal: 15 ``` Learn more about `chisel` [here](/chisel/overview). ### Installation If you encounter any issues during installation, refer to the [FAQ](/misc/faq) for assistance. #### Precompiled Binaries Precompiled binaries can be downloaded from the [GitHub releases page](https://github.com/foundry-rs/foundry/releases). For easier management, we recommend using [Foundryup](#using-foundryup). #### Using Foundryup Foundryup is the official installer for the Foundry toolchain. You can learn more about it [here](https://github.com/foundry-rs/foundry/blob/master/foundryup/README.md). To install Foundryup, open your terminal and run the following command: ```sh curl -L https://foundry.paradigm.xyz | bash ``` This will install Foundryup. Simply follow the on-screen instructions, and the `foundryup` command will become available in your CLI. Running `foundryup` will automatically install the latest `stable` version of the [precompiled binaries](#precompiled-binaries): `forge`, `cast`, `anvil`, and `chisel`. If you wish to use the latest `nightly` build run `foundryup --install nightly`. For additional options, such as installing a specific version or commit, run `foundryup --help`. If you want to install the binaries distributed by [Tempo's fork of Foundry](https://github.com/tempoxyz/tempo-foundry) run: ```sh foundryup -n tempo ``` This will install the latest `nightly` version of the [precompiled binaries](#precompiled-binaries): `forge` and `cast`. > ℹ️ **Note**\ > If you're using Windows, you'll need to install and use [Git BASH](https://gitforwindows.org/) or [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) as your terminal, since Foundryup currently doesn't support Powershell or Command Prompt (Cmd). ##### Verifying the integrity and provenance of binaries Foundry binaries are attested by using [GitHub artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds). When installing a release using `foundryup` we match the hashes of the binaries against the hashes of the Github attestation artifact. This guarantees that the binaries were built by our automated release process in the official Foundry repository. We also use these hashes to check whether you already have the version of the binary installed. If so, we will skip the downloading. You can pass the `--force` flag to skip the verification step. This also forces the installer to install a fresh version of the binaries as it has no hashes to match against. Note that in the case you install an older release you may find that no `*attestation.txt` are available in the release for `foundryup` to verify against. In this case verification is skipped at installation. You can at any time manually verify the integrity as follows: For example, `forge`: ```shell gh attestation verify --owner foundry-rs $(which forge) ✓ Verification succeeded! The following 1 attestation matched the policy criteria - Attestation #1 - Build repo:..... foundry-rs/foundry - Build workflow:. .github/workflows/release.yml@refs/tags/stable - Signer repo:.... foundry-rs/foundry - Signer workflow: .github/workflows/release.yml@refs/tags/stable ``` This is also the case for older releases. #### Building from Source ##### Prerequisites You'll need the [Rust](https://rust-lang.org) compiler and Cargo, Rust's package manager. The easiest way to install both is by using [`rustup.rs`](https://rustup.rs/). Foundry generally supports building only with the latest stable version of Rust. If you're using an older version of Rust, you can update it with `rustup`: ```sh rustup update stable ``` For Windows users, you'll also need a recent version of [Visual Studio](https://visualstudio.microsoft.com/downloads/), with the "Desktop Development With C++" workload installed. ##### Building You can either use the various flags provided by [Foundryup](#using-foundryup): ```sh foundryup --branch master foundryup --path path/to/foundry ``` Alternatively, you can install via Cargo with the following command: ```sh cargo install --git https://github.com/foundry-rs/foundry --profile release --locked forge cast chisel anvil ``` You can also manually build from a local copy of the [Foundry repository](https://github.com/foundry-rs/foundry): ```sh # clone the repository git clone https://github.com/foundry-rs/foundry.git cd foundry # install Forge cargo install --path ./crates/forge --profile release --force --locked # install Cast cargo install --path ./crates/cast --profile release --force --locked # install Anvil cargo install --path ./crates/anvil --profile release --force --locked # install Chisel cargo install --path ./crates/chisel --profile release --force --locked ``` #### CI Installation with GitHub Actions For instructions on setting up Foundry in a CI pipeline, refer to the [foundry-rs/foundry-toolchain](https://github.com/foundry-rs/foundry-toolchain) GitHub Action. #### Using Foundry with Docker :::note Some systems, including those with M1 chips, may experience issues when building the Docker image locally. This is a known issue. ::: Foundry can also be run inside a Docker container. If you don't have Docker installed, you can download it from [Docker's website](https://docs.docker.com/get-docker/). Once Docker is installed, you can pull the latest Foundry release by running: ```sh docker pull ghcr.io/foundry-rs/foundry:latest ``` You can also build the Docker image locally by running the following command from the Foundry repository: ```sh docker build -t foundry . ``` For examples and guides on using this image, refer to the [Docker guide](/guides/foundry-in-docker). #### Uninstalling Foundry contains everything in a `.foundry` directory, usually located in `/home//.foundry/` on Linux, `/Users//.foundry/` on MacOS and `C:\Users\\.foundry` on Windows where `` is your username. To uninstall Foundry remove the `.foundry` directory. :::warning The .foundry directory can contain keystores. Make sure to backup any keystores you want to keep. ::: Remove Foundry from PATH: * Optionally Foundry can be removed from editing shell configuration file (`.bashrc`, `.zshrc`, etc.). To do so remove the line that adds Foundry to PATH: ```sh export PATH="$PATH:/home/user/.foundry/bin" ``` ### Foundry Overview ![Foundry banner](/og-image.png) Foundry is a smart contract development toolchain. Foundry manages your dependencies, compiles your project, runs tests, deploys, and lets you interact with the chain from the command-line and via Solidity scripts. ### Navigating the Documentation #### Getting Started Get up and running with Foundry by [installing the toolkit](/introduction/installation) and [get started](/introduction/getting-started) with the basics of each tool. #### Guides Comprehensive tutorials and best practices for building robust smart contracts and development workflows with Foundry. * **Best Practices** * [Writing Contracts](/guides/best-practices/writing-contracts) - Guidelines for clean, secure smart contract development * [Writing Tests](/guides/best-practices/writing-tests) - Effective testing strategies and patterns * [Writing Scripts](/guides/best-practices/writing-scripts) - Deployment and automation script best practices * [Security](/guides/best-practices/security) - Security considerations and vulnerability prevention * [Key Management](/guides/best-practices/key-management) - Safe handling of private keys and secrets * [Commenting](/guides/best-practices/commenting) - Documentation and code commenting standards * [Scripting with Solidity](/guides/scripting-with-solidity) - Advanced deployment and automation techniques * [Deterministic deployments using CREATE2](/guides/deterministic-deployments-using-create2) - Predictable contract addresses * [Forking Mainnet with Cast and Anvil](/guides/forking-mainnet-with-cast-anvil) - Test against live chain state * [Running Foundry inside of Docker](/guides/foundry-in-docker) - Containerized development environments * [Implementing and Testing EIP-712 signatures](/guides/eip712) #### Project Setup Learn how to organize your projects with the [forge project setup guides](/guides/project-setup/creating-a-new-project) for scaling smart contract codebases. #### Forge Master the core smart contract development tool with the [Forge overview](/forge/overview), covering building, testing, deploying, and verifying contracts. #### Cast Learn to interact with blockchain networks from the command line using [Cast](/cast/overview) for contract calls, transactions, and chain data retrieval. #### Anvil Set up local development networks with [Anvil](/anvil/overview), Foundry's fast Ethereum-compatible node with forking capabilities. #### Chisel Explore Solidity interactively with [Chisel](/chisel/overview), the integrated REPL for rapid prototyping and debugging. #### Configuration Customize your Foundry setup and integrate with other tools for an optimized development workflow. * [Config Overview with `foundry.toml`](/config/overview) - Project configuration and settings * [Continuous Integration](/config/continuous-integration) - CI/CD pipeline integration * [Integrating with VSCode](/config/vscode) - Editor setup and extensions * [Shell Autocompletion](/config/shell-autocompletion) - Command-line productivity enhancements * [Static Analyzers](/config/static-analyzers) - Code analysis tool integration * [Integrating with Hardhat](/config/hardhat) - Cross-framework compatibility * [Vyper support](/config/vyper) - Alternative smart contract language support #### Contributing Help improve Foundry by contributing - see the [contribution guidelines](https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md) to learn more. #### Reference Complete command references, configuration options, and API documentation for all Foundry tools. * [FAQ](/misc/faq) - Frequently asked questions and troubleshooting * **Command References** * [forge Commands](/forge/reference/forge) - Complete forge CLI reference * [cast Commands](/cast/reference/cast) - Complete cast CLI reference * [anvil Commands](/anvil/reference) - Complete anvil CLI reference * [chisel Commands](/chisel/reference) - Complete chisel CLI reference * **Configuration & APIs** * [Config Reference](/config/reference/overview) - All configuration options * [Cheatcodes Reference](/reference/cheatcodes/overview) - Testing utilities and helpers * [Forge Standard Library Reference](/reference/forge-std/overview) - Standard library documentation * [DSTest Reference](/reference/ds-test) - Legacy testing framework reference :::tip You can also check out [Awesome Foundry](https://github.com/crisgarner/awesome-foundry), a curated list of awesome Foundry resources, guides, tools, and libraries! ::: ## Prompting One of the fastest ways to build smart contracts is by using AI to assist with writing boilerplate code, implementing complex testing patterns, and following security best practices. When building, iterating on, or debugging smart contracts using AI tools and Large Language Models (LLMs), a well-structured and extensive prompt helps provide the model with clearer guidelines and examples that can dramatically improve output quality. Below is an extensive example prompt that can help you build smart contracts using Foundry while adhering to the industries best practices. ### Build smart contracts using a prompt Use the structured prompt by copying and pasting it into your AI tool of choice (for example OpenAI's ChatGPT or Anthropic's Claude). **Make sure to enter your specific requirements at the end between the `` and `` tags** ````xml You are an advanced assistant specialized in Ethereum smart contract development using Foundry. You have deep knowledge of Forge, Cast, Anvil, Chisel, Solidity best practices, modern smart contract development patterns, and advanced testing methodologies including fuzz testing and invariant testing. - Respond in a clear and professional manner - Focus exclusively on Foundry-based solutions and tooling - Provide complete, working code examples with proper imports - Default to current Foundry and Solidity best practices - Always include comprehensive testing approaches (unit, fuzz, invariant) - Prioritize security and gas efficiency - Ask clarifying questions when requirements are ambiguous - Explain complex concepts and provide context for decisions - Follow proper naming conventions and code organization patterns - DO NOT write to or modify `foundry.toml` without asking. Explain which config property you are trying to add or change and why. - Use Foundry's default project structure: `src/` for contracts, `test/` for tests, `script/` for deployment scripts, `lib/` for dependencies - Write tests using Foundry's testing framework with forge-std - Use named imports: `import {Contract} from "src/Contract.sol"` - Follow NatSpec documentation standards for all public/external functions - Use descriptive test names: `test_RevertWhen_ConditionNotMet()`, `testFuzz_FunctionName()`, `invariant_PropertyName()` - Implement proper access controls and security patterns - Always include error handling and input validation - Use events for important state changes - Optimize for readability over gas savings unless specifically requested - Enable dynamic test linking for large projects: `dynamic_test_linking = true` Contract Files: - PascalCase for contracts: `MyContract.sol`, `ERC20Token.sol` - Interface prefix: `IMyContract.sol` - Abstract prefix: `AbstractMyContract.sol` - Test suffix: `MyContract.t.sol` - Script suffix: `Deploy.s.sol`, `MyContractScript.s.sol` Functions and Variables: - mixedCase for functions: `deposit()`, `withdrawAll()`, `getUserBalance()` - mixedCase for variables: `totalSupply`, `userBalances` - SCREAMING_SNAKE_CASE for constants: `MAX_SUPPLY`, `INTEREST_RATE` - SCREAMING_SNAKE_CASE for immutables: `OWNER`, `DEPLOYMENT_TIME` - PascalCase for structs: `UserInfo`, `PoolData` - PascalCase for enums: `Status`, `TokenType` Test Naming: - `test_FunctionName_Condition` for unit tests - `test_RevertWhen_Condition` for revert tests - `testFuzz_FunctionName` for fuzz tests - `invariant_PropertyName` for invariant tests - `testFork_Scenario` for fork tests Unit Testing: - Write comprehensive test suites for all functionality - Use `test_` prefix for standard tests, `testFuzz_` for fuzz tests - Test both positive and negative cases (success and revert scenarios) - Use `vm.expectRevert()` for testing expected failures - Include setup functions that establish test state - Use descriptive assertion messages: `assertEq(result, expected, "error message")` - Test state changes, event emissions, and return values - Write fork tests for integration with existing protocols - Never place assertions in `setUp()` functions Fuzz Testing: - Use appropriate parameter types to avoid overflows (e.g., uint96 instead of uint256) - Use `vm.assume()` to exclude invalid inputs rather than early returns - Use fixtures for specific edge cases that must be tested - Configure sufficient runs in foundry.toml: `fuzz = { runs = 1000 }` - Test property-based behaviors rather than isolated scenarios Invariant Testing: - Use `invariant_` prefix for invariant functions - Implement handler-based testing for complex protocols - Use ghost variables to track state across function calls - Test with multiple actors using proper actor management - Use bounded inputs with `bound()` function for controlled testing - Configure appropriate runs, depth, and timeout values - Examples: totalSupply == sum of balances, xy = k for AMMs - Implement reentrancy protection where applicable (ReentrancyGuard) - Use access control patterns (OpenZeppelin's Ownable, AccessControl) - Validate all user inputs and external contract calls - Follow CEI (Checks-Effects-Interactions) pattern - Use safe math operations (Solidity 0.8+ has built-in overflow protection) - Implement proper error handling for external calls - Consider front-running and MEV implications - Use time-based protections carefully (avoid block.timestamp dependencies) - Implement proper slippage protection for DeFi applications - Consider upgrade patterns carefully (proxy considerations) - Run `forge lint` to catch security and style issues - Address high-severity lints: incorrect-shift, divide-before-multiply Core Build & Test Commands: - `forge init ` - Initialize new Foundry project - `forge build` - Compile contracts and generate artifacts - `forge build --dynamic-test-linking` - Enable fast compilation for large projects - `forge test` - Run test suite with gas reporting - `forge test --match-test ` - Run specific tests - `forge test --match-contract ` - Run tests in specific contracts - `forge test -vvv` - Run tests with detailed trace output - `forge test --fuzz-runs 10000` - Run fuzz tests with custom iterations - `forge coverage` - Generate code coverage report - `forge snapshot` - Generate gas usage snapshots Documentation & Analysis: - `forge doc` - Generate documentation from NatSpec comments - `forge lint` - Lint Solidity code for security and style issues - `forge lint --severity high` - Show only high-severity issues - `forge verify-contract` - Verify contracts on Etherscan - `forge inspect ` - Inspect compiled contract metadata - `forge flatten ` - Flatten contract and dependencies Dependencies & Project Management: - `forge install ` - Install dependencies via git submodules - `forge install OpenZeppelin/openzeppelin-contracts@v4.9.0` - Install specific version - `forge update` - Update dependencies - `forge remove ` - Remove dependencies - `forge remappings` - Display import remappings Deployment & Scripting: - `forge script