Install Foundry v1.9.0 (foundryup --install v1.9.0), the version CI uses, and clone with submodules:
git clone --recurse-submodules https://github.com/ProjectOpenSea/seaport && cd seaportThe tests deploy precompiled artifacts, so build both profiles first. Rebuild them after changing contracts/, reference/, or a submodule.
FOUNDRY_PROFILE=reference forge build # reference-out/, via_ir off
FOUNDRY_PROFILE=optimized forge build # optimized-out/, via_ir onThe optimized build reproduces the deployed Seaport 1.6 init code byte for byte, and test/foundry/DeployedBytecode.t.sol fails if that ever changes.
FOUNDRY_PROFILE=test forge test # against the optimized build
FOUNDRY_PROFILE=reference MOAT_PROFILE=reference forge test # against the reference build
FOUNDRY_PROFILE=offerers forge test # contract offerer testsFOUNDRY_PROFILE=debugcompiles everything withoutvia_iror the optimizer, for full traces and source in the debugger. It doesn't match the deployed bytecode.FOUNDRY_PROFILE=moat_debugcompiles the fuzz engine intest/foundry/new/about twice as fast.
Coverage, with an HTML report. Seaport's core logic is in lib/seaport-core, so include libraries and filter out the rest, as CI does:
SEAPORT_COVERAGE=true forge coverage --report summary --report lcov --include-libs \
--no-match-coverage '(^|/)(test|script)/|^lib/(forge-std|murky|solarray|solady|solmate|openzeppelin-contracts|seaport-sol|seaport-types)/'
genhtml lcov.info -o html --branch && open html/index.htmlFuzz engine call counts, and the optimized build's distance from the 24,576-byte size limit:
SEAPORT_COLLECT_FUZZ_METRICS=true FOUNDRY_PROFILE=test forge test --match-path test/foundry/new/FuzzMain.t.sol
scripts/plot-metrics.sh call-metrics.txt
FOUNDRY_PROFILE=optimized forge build --sizesscripts/install-tools.sh # once: pinned tools into .tools/bin
scripts/lint.sh check
scripts/lint.sh fix
.tools/bin/lefthook install # optional pre-commit hookSolidity uses forge fmt and forge lint. TypeScript, JavaScript, JSON, Markdown, and YAML use Biome, TOML uses taplo, shell scripts use shellcheck and shfmt, and workflows use actionlint.
The install script downloads each tool from its GitHub release and checks it against a pinned SHA-256, so linting needs nothing from npm. It supports macOS and Linux; on Windows, use WSL. scripts/lint.sh runs the same checks as CI and warns when your Foundry version differs from CI's.
The deployed contracts (contracts/Seaport.sol, conduit/, helpers/, interfaces/, zones/) are excluded from forge fmt and forge lint, so their source stays identical to what was verified onchain. scripts/frozen-contracts.sha256 pins each of those files, and CI fails if one changes. After a deliberate change, regenerate it with scripts/lint.sh freeze.