ADR-004: Foundry as contract toolchain
- Status: Accepted
- Date: 2026-04-22
- Deciders: Core team
Context
Every Solidity project needs a build + test + deploy toolchain. The two mainstream options are:
- Foundry — Rust-based, tests written in Solidity, extremely fast, native fuzzing
- Hardhat — Node.js-based, tests written in JS/TS, large plugin ecosystem
Decision
Foundry as the primary contract toolchain. No Hardhat.Rationale
-
Tests in Solidity — contract tests written in the same language as the contracts means no type juggling, no ABI serialization in tests, and full access to cheatcodes (
vm.prank,vm.expectRevert,vm.warp). This is a meaningful correctness win. -
Speed —
forge testruns 10-100× faster than Hardhat for equivalent suites. For a project with fuzz + invariant tests running tens of thousands of cases, this matters. -
Native fuzzing and invariant testing — property-based testing is first-class in Foundry. For a naming protocol where "no one can steal another user's name" is an invariant, this is essential.
-
Gas snapshots built in —
forge snapshottracks gas usage per test, catching regressions in CI automatically. -
Active development — Foundry is the modern default for serious protocols (Uniswap v4, Morpho, Optimism, ENS tooling) and continues to ship improvements.
-
Simpler mental model — no separate JS test runner, no
hardhat.config.tswith plugin juggling. Justfoundry.tomland.solfiles.
Consequences
Positive
- Fast iteration loop (tests run in under a second for unit suites)
- Property-based testing as a first-class citizen
- Gas benchmarks automated in CI
- Smaller dependency footprint
Negative
- Deployment scripts written in Solidity can be awkward for complex orchestration
- Less mature plugin ecosystem vs Hardhat (e.g. no equivalent to OpenZeppelin Defender integration)
- Rust toolchain requirement may be novel for some contributors
Mitigations
- For multi-chain orchestrated deploys, we can supplement with a thin TypeScript deploy script using viem directly — no need to pull in Hardhat
foundryupinstaller is a single command and well-documented- Our CI pins a specific Foundry nightly version to avoid drift
Scope note
This ADR applies to the contracts/ workspace. TypeScript tooling (for indexer, SDK, web) is unaffected.

