Skip to content

AMT coverage: g3-entry-points - #99

Merged
thedavidmeister merged 3 commits into
mainfrom
2026-09-19-amt-g3-entry-points
Sep 20, 2026
Merged

thedavidmeister merged 3 commits into
mainfrom
2026-09-19-amt-g3-entry-points

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Adversarial mutation test of the four entry points in LibICloneableFactoryV4 (cloneDeterministic, predictDeterministicAddress, cloneDeterministicOpenSalt, predictDeterministicAddressOpenSalt) and the ICloneableV2 MUSTs the suite relies on in test/concrete/TestCloneable.sol. Scanned commit 5a633508643e345fc72c11133f782214f60db9b5. This PR changes tests only.

Tests

68 before, 71 after.

  • NEW testCloneDeterministicPredictCallerIndependent: the namespaced prediction, called from a pranked caller, equals the OZ oracle over keccak256(NAMESPACED, deployer, salt).
  • NEW testCloneDeterministicAddressIgnoresChainState and testCloneDeterministicOpenSaltAddressIgnoresChainState: with the factory funded and the block number and timestamp moved, both the prediction and the deployed address equal the oracle.
  • STRENGTHENED testCloneDeterministicOpenSaltPredictCallerIndependent: it now asserts equality with the oracle, where before it compared only alice with bob.
  • STRENGTHENED testTypedOverloadRevertsInitializeSignatureFn: it now checks the values 0 and type(uint256).max deterministically, on both the implementation and the clone, in addition to the fuzzed value.

Ledger

The verdicts come from mutation-probe, run first against the untouched suite at the scanned commit and then against this branch.

behaviour mutants verdict
cloneDeterministic derives effectiveSalt(msg.sender, salt) A01–A10, R01, R08, R18, S01–S03 KILLED_PREEXISTING
the same, independent of the factory balance and the block R14, R17 KILLED_NEW (testCloneDeterministicAddressIgnoresChainState)
cloneDeterministic emits the raw salt A10–A12, S04 KILLED_PREEXISTING (testCloneDeterministicEvent, testCloneDeterministicEventPrecedesInitialize)
cloneDeterministic forwards data to initialize, clones implementation and returns the child A13–A15, R11 KILLED_PREEXISTING
predictDeterministicAddress uses address(this) as the factory B01–B03, B09, S10 KILLED_PREEXISTING
predictDeterministicAddress uses deployer, not the caller, the origin or the factory B04–B06, B10, B11, R09, S06 KILLED_PREEXISTING
the same, when the caller has no code B12 KILLED_NEW (testCloneDeterministicPredictCallerIndependent)
predictDeterministicAddress derives with effectiveSalt over implementation B07, B08, B14, B15, R04, R06, S07–S09 KILLED_PREEXISTING
the same, independent of the factory balance R13 KILLED_NEW (testCloneDeterministicAddressIgnoresChainState)
cloneDeterministicOpenSalt derives effectiveOpenSalt(salt, data), with no caller term C01–C07, C13, R02, S11–S13 KILLED_PREEXISTING
the same, independent of the factory balance R15 KILLED_NEW (testCloneDeterministicOpenSaltAddressIgnoresChainState)
cloneDeterministicOpenSalt emits the raw salt C08, C09, R10, R20, S14 KILLED_PREEXISTING (testCloneDeterministicOpenSaltEvent)
cloneDeterministicOpenSalt forwards data, clones implementation and returns the child C10–C12, R12 KILLED_PREEXISTING
predictDeterministicAddressOpenSalt uses the factory term and no caller term D01–D05, D08, D09 KILLED_PREEXISTING (D09 by testCloneDeterministicOpenSaltPredictCallerIndependent, since strengthened)
predictDeterministicAddressOpenSalt derives from the salt, data and implementation D06, D07, D10, D12, D13, R03, R05, R19, S15–S19 KILLED_PREEXISTING
the same, independent of the factory balance and the block R07, R16 KILLED_NEW (testCloneDeterministicOpenSaltAddressIgnoresChainState)
both predictions are view B13, D11 EQUIVALENT: V3 and V4 declare them external view, and a non-view override does not compile
TestCloneable.initialize can run only once E01–E03, E12, E14, S20–S22, S24 KILLED_PREEXISTING (testInitializeOnlyOnce)
TestCloneable stores data and returns the literal sentinel E04, E10, S23 KILLED_PREEXISTING
the typed overload always reverts InitializeSignatureFn E05–E09, E13 KILLED_PREEXISTING (testTypedOverloadRevertsInitializeSignatureFn). Only the fuzzer killed E09 and E13, so the test is strengthened to make those kills deterministic.
TestCloneable writes the flag before the data E11 EQUIVALENT: initialize makes no external call between the two stores, so their order cannot be observed

Totals:

  • 113 distinct mutants were probed.
  • 103 were killed by the untouched suite, and 110 are killed after this PR.
  • 0 survive.
  • 3 are EQUIVALENT: B13, D11 and E11.

Dry: a re-survey of 23 new mutant shapes (S01–S24) against this branch killed all 23. The shapes were bit masking and forcing on the caller, deployer, factory, salt and implementation terms, data-length partitions, and alternate once-only guards.

QA

  • Discriminating tests: testCloneDeterministicPredictCallerIndependent, testCloneDeterministicAddressIgnoresChainState, testCloneDeterministicOpenSaltAddressIgnoresChainState, testCloneDeterministicOpenSaltPredictCallerIndependent (strengthened), testTypedOverloadRevertsInitializeSignatureFn (strengthened). Each passes on this branch and fails under its mutants. B12, R07 and R13–R17 survive the untouched suite at 5a63350, and this branch kills them. All results come from mutation-probe, with a green non-empty baseline, the proof regex (\d+) tests passed, (\d+) failed and the greedy fail-pattern \[FAIL.*\] (\S+).
  • Mutations applied:
    • predictDeterministicAddress returns a different address for a codeless caller → testCloneDeterministicPredictCallerIndependent;
    • the factory balance is mixed into the salt of each entry point (R07, R13, R14, R15) → the two …AddressIgnoresChainState tests;
    • the derivation ignores block.number/block.timestamp only when the value is past 1 (R16, R17) → the same two tests;
    • the typed overload returns for 0 or max (E09, E13) → testTypedOverloadRevertsInitializeSignatureFn;
    • the full per-mutant matrix is in the ledger above.
  • Oracle: OpenZeppelin Clones.predictDeterministicAddress over the interface formulas keccak256(abi.encode(NAMESPACED_DOMAIN, deployer, salt)) and keccak256(abi.encode(OPEN_SALT_DOMAIN, salt, keccak256(data))), written out in the tests, plus the ICloneableV2 MUSTs for the fixture. No expected value comes from the library under test.
  • Category check: the brief's g3 scope asks for derivation choice, argument order, the raw salt in the event, data in both places, the address(this)/deployer terms, view-ness, once-only initialize and the always-reverting typed overload. All eight are covered, as the ledger rows show. forge fmt --check is clean.

Findings

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Expanded validation for typed initialization overloads across uninitialized implementations and factory-created clones.
    • Added coverage confirming deterministic clone addresses remain independent of the caller.
    • Verified address predictions are unaffected by factory balance, timestamps, block numbers, or other chain-state changes.
    • Confirmed open-salt predictions match deployment results and standard CREATE2 address derivation.

thedavidmeister and others added 2 commits September 19, 2026 20:07
…the typed overload at 0 and max

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ce, block and timestamp

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Sep 19, 2026
@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 51003746-bcdc-40f9-8b2e-47a10ca84294

📥 Commits

Reviewing files that changed from the base of the PR and between 8cb4bf0 and 01be82a.

📒 Files selected for processing (3)
  • test/src/interface/ICloneableV2.initialize.t.sol
  • test/src/lib/LibICloneableFactoryV4.cloneDeterministic.t.sol
  • test/src/lib/LibICloneableFactoryV4.cloneDeterministicOpenSalt.t.sol

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The tests expand typed initialization revert coverage and verify that deterministic clone address predictions are independent of the caller, factory balance, timestamp, and block number.

Changes

Clone prediction and initialization tests

Layer / File(s) Summary
Typed initialization revert coverage
test/src/interface/ICloneableV2.initialize.t.sol
The test checks the supplied value, zero, and maximum uint256 against the expected revert on both the implementation and initialized clone.
Deterministic address invariants
test/src/lib/LibICloneableFactoryV4.cloneDeterministic.t.sol, test/src/lib/LibICloneableFactoryV4.cloneDeterministicOpenSalt.t.sol
The tests compare predictions with independent CREATE2 derivations. They verify caller independence and independence from factory balance, timestamp, and block number. Deployment is checked against the predicted address.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Other

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title identifies mutation-testing coverage for the g3 entry points, which matches the PR's main objective of adding adversarial mutation coverage tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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