Skip to content

Migrate test suite from Hardhat to Foundry#2848

Open
clement-ux wants to merge 128 commits intomasterfrom
clement/foundry-migration
Open

Migrate test suite from Hardhat to Foundry#2848
clement-ux wants to merge 128 commits intomasterfrom
clement/foundry-migration

Conversation

@clement-ux
Copy link
Copy Markdown
Collaborator

@clement-ux clement-ux commented Mar 20, 2026

Summary

Migrates the project's test suite from Hardhat to Foundry, introducing a comprehensive Foundry-based testing and deployment infrastructure. This is a large foundational PR that adds ~69,000 lines across 769 files, covering unit tests, fork tests, smoke tests, deployment tooling, CI, and AI-assisted development skills.

Migration note: This PR adds the Foundry test suite alongside the existing Hardhat tests. Hardhat tests will be removed in a follow-up PR once the team has verified that all tests have been correctly migrated and coverage is equivalent.

Foundry Test Suite (712 new test files, ~61,000 lines)

Unit tests covering 12 contract areas with high branch coverage:

  • Vault: OUSDVault, OETHVault — mint, redeem, rebase, yield, allocation, withdrawal queue, admin, governance, fuzz
  • Token: OUSD, OETH, OETHBase, OSonic, WOETH, WOETHBase, WOETHPlume, WOSonic, WrappedOusd
  • Strategies (15): CurveAMO, BaseCurveAMO, AerodromeAMO, NativeStakingSSV, CompoundingStakingSSV, SonicStaking, SonicSwapXAMO, CrossChainMaster, CrossChainRemote, Generalized4626, BridgedWOETH, VaultValueChecker, MorphoV2, OETHSupernovaAMO, ConsolidationController
  • Pool Boosters: Curve, Merkl, SwapX (single/double), Metropolis, CentralRegistry
  • Beacon/Validator: BeaconProofsLib, Endian, Merkle
  • Other: Proxies, Governance, Automation (Safe modules), Zappers, Bridges, Harvest, Oracle

Fork tests across 3 chains (Mainnet, Base, Sonic):

  • All major strategies with real on-chain state
  • Beacon proofs, partial withdrawals, beacon roots
  • Pool boosters (Curve, SwapX, Merkl, Metropolis, Shadow)
  • Safe automation modules

Smoke tests across 4 chains (Mainnet, Base, Sonic, HyperEVM):

  • End-to-end mint/redeem/rebase flows for OUSD, OETH, OETHBase, OSonic
  • Wrapped token deposit/withdraw roundtrips
  • All strategy-specific smoke tests
  • Pool booster and automation smoke tests
  • Uses DeployManager/Resolver to apply pending governance before testing

Deployment Infrastructure

  • DeployManager & Resolver: Solidity-native deployment framework that reads deployment JSONs, resolves contract addresses, and applies pending governance actions in fork environments
  • Chain-specific deploy scripts: Mainnet, Base, Sonic, HyperEVM with example templates
  • Deployment registry JSONs: build/deployments-{1,146,8453,999}.json mapping contract names to addresses

CI/CD (foundry.yml workflow)

  • Replaces the legacy defi.yml workflow
  • 10 parallel jobs: formatting/lint, contract size check, unit tests, coverage, fork tests (Mainnet/Base/Sonic), smoke tests (Mainnet/Base/Sonic/HyperEVM)
  • Foundry setup action with Soldeer dependency installation, build caching
  • Slither static analysis and Snyk security scanning jobs

Tooling & DX

  • Makefile: 40+ targets for build, test, fork, smoke, coverage, deploy, and formatting
  • .env.example: Documents all required/optional environment variables
  • AI skills (Claude Code & Codex): unit-test, fork-test, smoke-test, commit — codified conventions for generating tests that follow project patterns
  • BeaconProofs fixture: Pre-computed beacon proof data committed to repo, eliminating ~10min beacon RPC calls in CI

Cleanup

  • Removed legacy Echidna fuzzing contracts (13 files, ~1,345 lines)
  • Removed unused MockRebornMinter contract
  • Removed legacy defi.yml CI workflow
  • Applied Prettier formatting to Solidity files

Test plan

  • make test — run all Foundry unit tests
  • make test-fork-mainnet — run mainnet fork tests
  • make test-fork-base — run Base fork tests
  • make test-fork-sonic — run Sonic fork tests
  • make test-smoke-mainnet — run mainnet smoke tests
  • make coverage — verify coverage meets thresholds
  • CI workflow passes all 10 jobs on the PR branch
  • Existing Hardhat tests unaffected (pnpm test still passes)

clement-ux and others added 30 commits March 2, 2026 09:52
Set up forge compilation for all 302 Solidity files alongside existing
Hardhat config. Add foundry.toml with Soldeer deps (forge-std, OZ 4.4.2,
Chainlink CCIP, LayerZero v2, solidity-bytes-utils) and transitive
remappings for LZ dependency chain. Replace hardhat/console.sol import
with forge-std/console2.sol in MockRebornMinter.
Add MockStrategy and MockNonRebasing state variables and imports
to the shared Base contract so they are available to all test suites.
Shared.sol deploys OUSD + OUSDVault behind proxies, configures the
vault with withdrawal delay, rebase rate max, and drip duration,
then funds matt and josh with 100 OUSD each.

Mint.t.sol covers mint, deprecated mint overload, mintForStrategy,
burnForStrategy, and auto-allocate on mint (13 tests).
Cover governor(), isGovernor(), two-step transferGovernance +
claimGovernance flow, and access control reverts (9 tests).
Cover totalValue, checkBalance, getAssetCount, getAllAssets,
getStrategyCount, getAllStrategies, isSupportedAsset, and the
deprecated oUSD() accessor (18 tests).
Cover all VaultAdmin setters, pause functions, strategy management,
and token rescue. Includes revert paths for unauthorized callers,
invalid values, and edge cases like "Asset not supported by Strategy",
"Strategy has funds", and "Parameter length mismatch" (98 tests).
Cover rebase pausing, yield distribution to rebasing accounts,
non-rebasing exclusion, trustee fee accrual, previewYield,
drip duration smoothing, _nextYield early-return branches, and
the defensive fee >= yield check (19 tests).
Cover allocate to default strategy, vault buffer, withdrawal queue
reserves, depositToStrategy, withdrawFromStrategy,
withdrawAllFromStrategy, withdrawAllFromStrategies, capital-paused
revert, and early return when no asset available (23 tests).
Cover requestWithdrawal, claimWithdrawal, claimWithdrawals,
addWithdrawalQueueLiquidity, strategy-queue interactions,
mint-covers-outstanding scenarios, full drain edge cases,
insolvency and slash scenarios, solvency at 3%/10%
maxSupplyDiff, rebase-on-redeem, and capital-paused claims
(55 tests).
Add test directory, solmate dependency, and remappings to
foundry.toml. Add .gitkeep placeholders for the test directory
structure. Add lcov.info to .gitignore.
Captures the established test conventions (directory layout, inheritance
chain, naming patterns, helper idioms, fuzz config) so future contract
test suites follow the same structure as OUSDVault.
Add fuzz tests for mint, rebase, and withdraw covering key properties
(scaling, round-trip recovery, yield distribution, queue invariants).
Configure foundry.toml with 1024 runs and deterministic seed.
…to 96%

- Add Burn.t.sol and Initialize.t.sol for previously untested functions
- Add missing revert tests to Mint, TransferFrom, Transfer, YieldDelegation
- Fix truncated assertion in Mint.t.sol
- Update unit-test skill to enforce one file per function rule
Enforce minimum coverage thresholds: 100% functions, 90% branches/lines/statements.
Includes iterative improvement workflow and requires explanation for uncovered paths.
…onic, WrappedOusd)

Add Foundry unit tests for remaining wrapped token variants and declare
their state variables in Base.sol for shared test infrastructure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r contracts

Add comprehensive unit tests for OETHZapper, OETHBaseZapper, OSonicZapper,
and WOETHCCIPZapper. Tests cover all public functions, revert conditions,
event emissions, and edge cases. Uses vm.mockCall for CCIP router and
vm.etch for hardcoded addresses (wS, Base WETH).

35 tests across 9 test suites — 100% line/statement/branch/function coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…% coverage

Add 120 tests across 22 files covering CurvePoolBooster, CurvePoolBoosterPlain,
and CurvePoolBoosterFactory. Includes concrete tests for all public/external
functions and fuzz tests for fee handling and salt encoding.

Also adds shared test infrastructure: Base.sol pool booster state vars,
MockCreateX for deterministic CREATE2 testing, and naming convention rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add unit tests for PoolBoosterMerkl and PoolBoosterFactoryMerkl covering
constructor, bribe, isValidSignature, getNextPeriodStartTime, factory
create/compute, and setMerklDistributor. Includes fuzz test for period timing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add unit tests for PoolBoosterSwapxSingle, PoolBoosterSwapxDouble, and their
factories. Covers constructor validation, bribe mechanics, split calculations,
factory create/compute, and abstract factory functions (bribeAll, removePoolBooster).
Includes fuzz test for double bribe split amounts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add unit tests for PoolBoosterMetropolis and PoolBoosterFactoryMetropolis
covering constructor, bribe mechanics with rewarder/voter mocking, and
factory create/compute functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…overage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensures forge excludes test helper files from coverage reports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…h 100% coverage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rnovaAMOStrategy

- 18 unit test files (80 tests): constructor, deposit, withdraw, rebalance, fuzz
- 7 fork test files (72 tests): fresh pool/gauge via factory authorization, front-running, insolvency
- 6 smoke test files (19 tests): deployed contract validation via Resolver
- Infrastructure: add Supernova addresses to Addresses.sol, strategy to Base.t.sol, proxy to deployments-1.json
…deployment setup

- Add HyperEVM RPC endpoint to foundry.toml and fork helper in BaseFork.t.sol
- Add HyperEVM chain routing (ID 999) to DeployManager and Base.s.sol
- Create example deploy script in scripts/deploy/hyperevm/
- Create deployments-999.json with CrossChainRemoteStrategy address
- Add HyperEVM smoke tests (ViewFunctions, BalanceUpdate, Deposit, Withdraw, RelayValidation)
- Add fork-tests-hyperevm and smoke-tests-hyperevm CI jobs in foundry.yml
- Rename CrossChainRemoteStrategy smoke tests to CrossChainRemoteStrategyBase
- Cache forge build artifacts (out/, cache/) to avoid recompiling 1007 files each job
- Remove `needs: build` gate so test jobs start immediately in parallel
- Split Fork Tests (Mainnet) into 3 matrix chunks for parallel execution
- Skip foundry-setup entirely when no tests discovered for a chain
…Strategy

- Unit tests (31): deposit, withdraw, withdrawAll override, maxWithdraw,
  view functions, and fuzz tests with limited liquidity simulation
- Fork tests (20): fresh deploy against real Morpho V2 vault on mainnet
  fork with mocked share guard for whitelist bypass
- Smoke tests (14): deployment health checks via DeployManager/Resolver
- Add MockMorphoV2Vault and MockMorphoV2Adapter for unit test isolation
- Register MORPHO_OUSD_V2_STRATEGY_PROXY in deployments-1.json
…alls

- Commit pre-generated beacon proof fixture for slot 12235962 (20KB JSON)
- Read fixture via vm.readFile() with FFI fallback for custom slots
- Narrow forge build cache to exclude 273MB beacon SSZ state files
- Reduce Mainnet fork chunks from 3 to 2 now that BeaconProofs is instant
…olidationController

- Fork tests extend BaseFork with fresh OETH+OETHVault deployment
- Strategy proxies upgraded to new impls pointing at fresh vault
- Unit tests cover request/fail/confirm consolidation and operations
- Smoke tests validate deployed configuration and forwarding
- Add missing addresses to Addresses.sol (FeeAccumulators, BeaconProofs)
…s and fix HyperEVM smoke tests

- Move fork/smoke tests into chain-specific subdirs (mainnet/, base/, sonic/, hyperevm/)
- Update CI workflow to use `find` with chain-specific paths instead of `grep -rl`
- Fix HyperEVM smoke tests: mock CCTP MessageTransmitter and TokenMessenger
  to avoid arithmetic overflow from real on-chain CCTP contracts
- Run forge fmt on all test/script files to fix formatting
- Add Makefile with targets for build, test, deploy, coverage, and gas
- Multi-chain support (mainnet, base, sonic, hyperevm) for test and deploy
- Reorganize dev.env with consistent sections and annotations
@clement-ux clement-ux changed the title Clement/foundry migration Migrate test suite from Hardhat to Foundry with CI, deployment infrastructure, and AI-assisted skills Mar 23, 2026
@clement-ux clement-ux changed the title Migrate test suite from Hardhat to Foundry with CI, deployment infrastructure, and AI-assisted skills Migrate test suite from Hardhat to Foundry Mar 23, 2026
The fork test was failing because the on-chain SSV validator state had
changed, causing IncorrectValidatorStateWithData to revert before
reaching the existing try-catch on removeSsvValidator. Both SSV calls
are now wrapped since the test validates access control, not SSV state.
@clement-ux clement-ux marked this pull request as ready for review March 23, 2026 11:57
clement-ux and others added 9 commits March 23, 2026 13:05
Wrap exitSsvValidator calls in try-catch to handle
IncorrectValidatorStateWithData from the SSV Network when validators
have already been exited on-chain. Falls back to vm.store where the
test needs the EXITING state for subsequent assertions.
…ilation

Base.t.sol imported ~60 contracts and was inherited by ~99 Shared.t.sol
files. Any change to it invalidated the entire Foundry cache, triggering
a full recompile. Strip Base.t.sol to only actors, constants, IERC20
external tokens, fork IDs, and setUp(). Move typed contract/proxy/mock
variable declarations into each Shared.t.sol that actually uses them.

Also add a [profile.test] section to foundry.toml with optimizer disabled
and dynamic_test_linking enabled for faster test-only compilation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verify deployment health for all four vault contracts via DeployManager/Resolver:
- ViewFunctions: governor, strategist, default strategy, vault buffer, claim delay, pause states
- Mint: totalValue increase, asset debit, vault receives asset
- Rebase: succeeds, increases supply, previewYield correctness
- Allocate: depositToStrategy, withdrawFromStrategy, totalValue preservation
- WithdrawalQueue: metadata updates, multi-claim, liquidity management, request storage
Standalone Node.js script that compares storage layouts between git refs
using forge inspect. Reviewers can run it during PR review to verify
upgrades won't cause storage slot conflicts.
- Add --json flag to forge inspect and strip tracing logs from stdout
- Install soldeer dependencies before building in worktrees
- Make forge build non-fatal (partial builds can still inspect some contracts)
- Handle the "carve from gap" upgrade pattern: new variables replacing
  the start of a __gap array are valid if the gap shrinks by the exact
  number of slots used
…hecker

- Use install-deps.sh instead of forge soldeer install (handles npm tgz packages)
- Run forge clean before building to avoid stale cache issues
- Add extra_output_files = ["storageLayout"] to foundry.toml
Only compiles the target contract and its dependencies, not the entire
repo. Reduces runtime from ~3min to ~10s per contract check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant