Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new Foundry fuzz/invariant testing suite under test/fuzz to broaden coverage of vault components (StakingVault/Dashboard/VaultHub), PDG accounting, and several shared libraries.
Changes:
- Added invariant suites for
RefSlotCacheandPredepositGuaranteeaccounting. - Added fuzz suites for StakingVault (direct + Dashboard integration) and CLProofVerifier.
- Added fuzz/property suites for multiple shared libraries plus VaultHub/LazyOracle and Lido share-accounting integrations.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
test/fuzz/vaults/refSlotCache.invariant.t.sol |
Extended invariant coverage for DoubleRefSlotCache with multi-slot jumps and revert conditions. |
test/fuzz/vaults/refSlotCache.fuzz.t.sol |
Baseline invariant fuzzing for DoubleRefSlotCache behaviors. |
test/fuzz/vaults/predepositGuarantee.invariant.t.sol |
Invariant suite for PDG bond/accounting conservation with ghost tracking. |
test/fuzz/vaults/clProofVerifier.fuzz.t.sol |
Fuzz tests for CLProofVerifier gindex selection and revert behavior. |
test/fuzz/vaults/StakingVaultDirect.fuzz.t.sol |
Fuzz tests for direct (no Dashboard/VaultHub) StakingVault access control + accounting. |
test/fuzz/vaults/StakingVaultDashboard.fuzz.t.sol |
Integration fuzz tests for Dashboard → VaultHub → StakingVault call paths using local mocks. |
test/fuzz/lib/TriggerableWithdrawals.fuzz.t.sol |
Property/fuzz tests for TriggerableWithdrawals validation and mock-precompile happy paths. |
test/fuzz/lib/MinFirstAllocationStrategy.fuzz.t.sol |
Property/fuzz tests for allocation invariants (budget conservation, caps, monotonicity). |
test/fuzz/lib/MeIfNobodyElse.fuzz.t.sol |
Property/fuzz tests for mapping-default behavior used by PDG. |
test/fuzz/lib/Math256.fuzz.t.sol |
Property/fuzz tests for Math256 helpers (min/max/ceilDiv/absDiff). |
test/fuzz/lib/GIndex.fuzz.t.sol |
Property/fuzz tests for GIndex arithmetic + bounds/reverts and concat behavior. |
test/fuzz/lib/BLS.fuzz.t.sol |
Extensive fuzz/edge-case tests around BLS12-381 deposit verification and flag validation. |
test/fuzz/integration/VaultHubLazyOracle.fuzz.t.sol |
Integration fuzz tests for VaultHub lifecycle + report freshness/quarantine timestamp semantics. |
test/fuzz/integration/LidoIntegration.fuzz.t.sol |
Integration fuzz tests for Lido external-shares accounting vs VaultHub liability shares. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function vaultRecord(address) external pure returns (VaultHub.VaultRecord memory) {} | ||
|
|
||
| function latestReport(address) external pure returns (VaultHub.Report memory) {} |
There was a problem hiding this comment.
vaultRecord() and latestReport() have empty bodies but declare non-void return types. As written this won’t compile (functions must return a value unless using named return variables). Implement minimal stub returns (e.g., return zero-initialized structs via named return vars) or remove these functions if they are not needed for the Dashboard code paths exercised in this test.
| function vaultRecord(address) external pure returns (VaultHub.VaultRecord memory) {} | |
| function latestReport(address) external pure returns (VaultHub.Report memory) {} | |
| function vaultRecord(address) external pure returns (VaultHub.VaultRecord memory record) {} | |
| function latestReport(address) external pure returns (VaultHub.Report memory report) {} |
| function testFuzz_getValidatorGI_UsesPrevBeforePivot(uint64 provenSlot, uint32 offset) external view { | ||
| vm.assume(provenSlot < pivotSlot); | ||
|
|
||
| // Bound offsets to avoid expected IndexOutOfRange reverts from GIndex.shr(). | ||
| uint256 boundedOffset = bound(uint256(offset), 0, 1_000_000); | ||
|
|
||
| GIndex expected = giPrev.shr(boundedOffset); |
There was a problem hiding this comment.
This test is marked external view but calls vm.assume(...), which is a cheatcode call and not view-compatible. This will fail to compile due to calling a non-view function from a view function. Drop the view mutability on this test (and keep it external) so it can use vm.assume/cheatcodes.
| function testFuzz_getValidatorGI_UsesCurrAtOrAfterPivot(uint64 provenSlot, uint32 offset) external view { | ||
| vm.assume(provenSlot >= pivotSlot); | ||
|
|
||
| uint256 boundedOffset = bound(uint256(offset), 0, 1_000_000); | ||
|
|
||
| GIndex expected = giCurr.shr(boundedOffset); |
There was a problem hiding this comment.
This test is marked external view but uses vm.assume(...) (cheatcode), which cannot be invoked from a view function and will cause a compile-time error. Remove view from the function signature.
| function testFuzz_LI6_sharePriceRoundTrip(uint96 ethAmount) external view { | ||
| vm.assume(ethAmount > 0 && ethAmount < 1_000_000 ether); | ||
|
|
||
| uint256 shares = lido.getSharesByPooledEth(ethAmount); | ||
| uint256 ethBack = lido.getPooledEthByShares(shares); | ||
|
|
||
| // Due to floor division, ethBack may be 1 wei less than ethAmount | ||
| assertGe(uint256(ethAmount) + 1, ethBack, "LI-6: round-trip lost too much"); | ||
| assertGe(ethBack + 1, uint256(ethAmount), "LI-6: round-trip gained too much"); |
There was a problem hiding this comment.
testFuzz_LI6_sharePriceRoundTrip is declared external view but calls vm.assume(...). Cheatcode calls are not view-compatible, so this will not compile. Remove view from the function signature.
Summary
test/fuzzIncluded files
test/fuzz/integration/*test/fuzz/lib/*test/fuzz/vaults/*