Skip to content

Add invariant test suite#468

Open
wischli wants to merge 455 commits intomainfrom
wf/feat/recon-invariants
Open

Add invariant test suite#468
wischli wants to merge 455 commits intomainfrom
wf/feat/recon-invariants

Conversation

@wischli
Copy link
Contributor

@wischli wischli commented Jun 24, 2025

Summary

Adds a comprehensive invariant testing suite under test/integration/recon-end-to-end/ using the Recon/Chimera framework. The suite deploys the full Hub + Spoke stack on-chain and uses Echidna (assertion mode) to explore multi-step call sequences that could violate protocol guarantees.

29 new files, ~10,200 lines covering 131 properties across vault operations, ERC-7540 compliance, deposit/redeem lifecycle, share accounting, escrow balance integrity, and authorization.

Also adds root-level config: echidna.yaml, medusa.json, foundry.toml remappings, and lib/setup-helpers submodule.

What This Tests

The fuzzer calls target functions in random order with random inputs, then checks that protocol invariants still hold. Properties are organized into categories:

Category Count Examples
Vault max* correctness 20 deposit(maxDeposit) blocks further deposits; maxMint consistent with maxDeposit
ERC-7540 compliance 13 max* never reverts; preview* always reverts; claim > max always reverts
Deposit/redeem lifecycle 24 pending amounts track correctly; cancel amounts bounded; claim deltas match escrow
Share accounting 12 sum of balances = totalSupply; supply consistency; PPS never changes after user ops
Price & proportionality 6 deposit/redeem prices bounded by fulfillment price; asset-share proportionality
BalanceSheet queue state 10 queue counters consistent; nonace monotonic; reserve/unreserve integrity
Authorization 3 ward checks can't be bypassed; auth level correct; auth changes tracked
Doomsday edge cases 12 zero price handled gracefully; operations below max always succeed; accountValue never reverts
Inline target assertions 31 escrow balance deltas on issue/revoke, deposit/redeem claims, transfer restrictions

Full table: test/integration/recon-end-to-end/properties-table.md
Suite README: test/integration/recon-end-to-end/README.md

Echidna Results

128 of 131 properties pass. The 3 failures are acknowledged false positives, not protocol bugs:

Property Status Why
property_authorizationBypass ❌ Acknowledged Admin can bypass BalanceSheet auth by skipping updateBalanceSheetManager — unrealistic operational mistake
vault_maxWithdraw ❌ Acknowledged Direct balanceSheet.issue() call outside normal manager flow — admin workflow violation
property_availableGtQueued ❌ Acknowledged BalanceSheet queue vs available balance tracking — edge case under investigation

Details: .claude/docs/recon/13-acknowledged-risks.md

Not Covered (Future Work)

The suite tests the core deposit/redeem lifecycle end-to-end but does not yet cover:

  • VaultRouter — omitted from setup; vault functions are called directly
  • Cross-chain messaging — Hub and Spoke are deployed on the same chain; no adapter or Gateway message round-trips are tested
  • Manager contracts — NAVManager, QueueManager, OnOfframpManager, MerkleProofManager are not exercised
  • Multiple asset types — only standard ERC-20 assets (tokenId=0); no ERC-721/1155 flows
  • Valuation contracts — OracleValuation is not wired; only IdentityValuation used

Potential follow-ups based on Echidna findings:

  1. Async vault rounding dustdeposit(maxDeposit) can leave maxMint > 0 due to shares↔assets conversion precision loss. Protocol recommends mint(maxMint) for full consumption. Consider documenting this for integrators.
  2. BalanceSheet manager auth setup — the property_authorizationBypass finding suggests deployment tooling should enforce updateBalanceSheetManager is always called. Worth a defensive check or deployment script assertion.
  3. Multi-vault ghost tracking — properties that track price-per-share across vault switches can produce false positives. This is a test infrastructure limitation, not a protocol issue.

How to Run

# Foundry reproducers (fast, runs existing failure sequences)
forge test --match-path test/integration/recon-end-to-end/CryticToFoundry.sol -vvv

# Local Echidna campaign (slow, explores new sequences)
echidna . --contract CryticE2ETester --config echidna.yaml --format text --workers 16 --test-limit 100000000

@wischli wischli self-assigned this Mar 3, 2026
@wischli wischli requested a review from onnovisser March 3, 2026 16:04
@wischli wischli marked this pull request as ready for review March 3, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants