LibICloneableFactoryV4: the whole factory logic as a unit-tested library - #59
Conversation
… library The library half of the split carries the logic, not just the interfaces: both V4 effective-salt derivations, the implementation-code guard, the EIP1167 creation code and CREATE2 prediction constructed from the standard's own bytes, and the atomic clone-initialize-verify flow with typed errors and NewClone. msg.sender and address(this) are read inside the library, so a concrete factory is one delegation per entry point — TestCloneFactory in the suite is exactly that concrete, and the deploy half's CloneFactory is meant to become it. The published src/ imports nothing external; OZ Clones is vendored as a test-only oracle pinning the EIP1167 construction byte for byte, next to the raw CREATE2 formula and the EIP's literal bytes restated in-test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README, CLAUDE.md and the release workflow all asserted the post-split interface-only shape; LibCloneFactory makes them stale. CLAUDE.md stays under its 4096-byte agent-context cap by cutting, not raising. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s branch prettier-rainix, taplo and yamlfmt normalize .vscode/settings.json, slither.config.json, REUSE.toml and .coderabbitai.yaml — all untouched by the feature commits; main fails the all-files run the same way. Mechanical output only, committed so the branch gate runs clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New generated file with no header capability; listed in the annotations path array per rain.extrospection's precedent. reuse lint is compliant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 11 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (19)
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. Comment |
…ranch Conflicts resolved in CLAUDE.md, README.md and REUSE.toml by taking main's framing — the repo is the interface surface plus the LibICloneableFactoryV4 library — extended to cover the factory logic this branch adds. The lib/test fold onto #58's surface is the next commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ruling (thedavidmeister, 2026-08-20): #58's design wins. Its LibICloneableFactoryV4 — the interface-mirroring lib carrying the two effective-salt derivations — is the shape; this branch's LibCloneFactory must not stand next to it as a parallel second lib. So: LibCloneFactory's duplicate derivations (effectiveSaltNamespaced / effectiveSaltOpen) are deleted in favour of the merged effectiveSalt / effectiveOpenSalt, which stay byte-identical to #58. Everything else — the EIP-1167 creation code and CREATE2 prediction, the implementation-code guard, the atomic clone-initialize-verify flow with its typed errors, and the four ICloneableFactoryV4 entry points — folds into LibICloneableFactoryV4 beneath them, delegating to the merged derivations. The internal salt parameter is renamed derivedSalt so it cannot shadow the effectiveSalt function it now sits beside. The lib's pragma moves ^0.8.18 -> ^0.8.25: the flow emits the interface's NewClone via qualified access (ICloneableFactoryV3.NewClone), which needs solc >= 0.8.21, and this repo's convention is that libraries float ^0.8.25 while interfaces keep ^0.8.18. Tests follow the fold: the merged LibICloneableFactoryV4.t.sol gains the six non-duplicate derivation tests (preimage shape and input sensitivity, renamed to the merged function names); the two LibCloneFactory derivation suites are deleted as duplicates of what #58 already covers; the five machinery/flow suites are renamed LibICloneableFactoryV4.*.t.sol and retargeted, as is the TestCloneFactory pure-delegation harness. 42 tests, 6 suites, fuzz 2048, all green; .gas-snapshot regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Line-wrapping only; no content change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI's static gate runs forge fmt --check, which this repo's pre-commit does not; formatted with the pinned toolchain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The library half of the library/deploy split (#46) has been interface-only; the ruling (thedavidmeister, 2026-08-20) is that it must not be: the library repo carries interfaces plus Lib* logic, unit tested; the deploy repo keeps a thin concrete that only delegates, plus deploy pins and equivalence tests. This PR delivers the rain.factory half only; slimming rain.factory.deploy's
CloneFactoryto pure delegation is a follow-up PR in that repo.Reworked on top of #58
This branch originally added the logic as a parallel
src/lib/LibCloneFactory.sol. While it was open, #58 mergedLibICloneableFactoryV4— the interface-mirroring library carrying the two effective-salt derivations — and the ruling (thedavidmeister, 2026-08-20) is that #58's design wins: one lib, named for the interface it implements. Somainis merged in and the factory logic is folded intoLibICloneableFactoryV4:src/lib/LibCloneFactory.sol, including its duplicate derivationseffectiveSaltNamespaced/effectiveSaltOpen, in favour of Extract ICloneableFactoryV4 salt-derivation math into LibICloneableFactoryV4 #58'seffectiveSalt/effectiveOpenSalt(byte-identical formulas; Extract ICloneableFactoryV4 salt-derivation math into LibICloneableFactoryV4 #58's names and argument order govern).LibICloneableFactoryV4: the EIP-1167 creation code and CREATE2 prediction, the implementation-code guard, the atomic clone-initialize-verify flow with its typed errors, and the fourICloneableFactoryV4entry points — all now delegating to the merged derivations.derivedSaltso it cannot shadow theeffectiveSaltfunction it now sits beside; the five machinery/flow test suites areLibICloneableFactoryV4.*.t.sol.^0.8.18→^0.8.25(qualifiedICloneableFactoryV3.NewCloneemission needs solc >= 0.8.21; repo convention is libs float^0.8.25, interfaces keep^0.8.18).The library surface
src/lib/LibICloneableFactoryV4.sol, all internal, no external imports in publishedsrc/(OZ is vendored test-only as the equivalence oracle; withrecursive_deps = falsean OZ import insrc/would land in every downstream consumer's manifest):effectiveSalt(deployer, salt)/effectiveOpenSalt(salt, data)— from Extract ICloneableFactoryV4 salt-derivation math into LibICloneableFactoryV4 #58, unchanged: the two derivations exactly asICloneableFactoryV4pins them, akeccak256over a 96-byte preimage led by a distinct string-derived domain tag imported from the interface.cloneCreationCode(implementation)/predictCloneAddress(factory, implementation, derivedSalt)— the EIP-1167 creation code and its CREATE2 prediction built from the standard's own bytes.checkImplementationCode(implementation)— the zero-code guard.cloneAndInitialize(implementation, derivedSalt, data, salt)— the shared tail: guard → CREATE2 →NewClonewith the RAW caller salt →initializeverified againstICLONEABLE_V2_SUCCESS, atomic per the V3/V4 spec.cloneDeterministic/predictDeterministicAddress/cloneDeterministicOpenSalt/predictDeterministicAddressOpenSalt— the four entry points, whole.msg.senderandaddress(this)are read INSIDE the library, so a delegating concrete cannot namespace by anything else and there is no sender parameter to misroutetx.origininto.Typed errors at file level:
ZeroImplementationCodeSize,CloneDeploymentFailed,InitializationFailed. No named return values anywhere.test/src/concrete/TestCloneFactory.solis the executable proof of the surface: a concreteICloneableFactoryV4whose four functions are one delegation each; the flow tests run through it.Divergences found
_effectiveSaltis not the V4 derivation. It hashes the untagged 64-byteabi.encode(deployer, salt)— V3-era, predating the tags. The interface NatSpec is the spec and pins the tagged 96-byte preimage; the library implements the spec. Nothing is released from the new lane, so no deployed factory changes behaviour; a V4 factory's namespaced addresses differ from the V3 factory's regardless, since the factory address is inside CREATE2.rain.factory.deploy@factory/open-salt-clone-deployis stale against the current interface. Written against rain-factory 0.1.7, it tags only the open derivation and keeps the namespaced one untagged. Main's interface has since pinned BOTH tags and derives disjointness from the two fixed words. That branch's suite was mined for intent; its untagged-squat test is reworked astestCloneDeterministicOpenSaltDisjointTagsCloseTheSquat.Errors.FailedDeployment. Library: typedCloneDeploymentFailed. Nothing released from the new lane depends on the OZ error.Tests
42 tests across 6 suites, fuzz runs 2048, one file per library concern: the merged
LibICloneableFactoryV4.t.solcarries #58's derivation pins plus the six non-duplicate derivation tests from this branch (preimage shape and input sensitivity, renamed to the merged function names); the five machinery/flow suites exercise the creation code, prediction, guard, and both clone flows throughTestCloneFactory.QA
ICloneableFactoryV4NatSpec equations restated in-test; the domain tags re-derived from their documented strings (keccak256("rain.factory.clone.namespaced")/keccak256("rain.factory.clone.opensalt")); the EIP-1167 creation and runtime bytes written literally in-test from the EIP; OZClones5.6.1 as a foreign implementation of the same prediction; the raw CREATE2 formula longhand. No expected value is computed by the code under test.nix run github:rainlanguage/adversarial-mutation-test#mutation-probe -- mutants.toml, over a 16-mutant matrix — one mutant per moved/kept behavior, every target insrc/lib/LibICloneableFactoryV4.sol, never in test code; suite commandnix develop -c forge test(fuzz 2048) per verdict. Probe output, transcribed:pre-commit run --all-files,nix develop -c forge test(42 passed, 0 failed),reuse lint— all green on the pushed head.🤖 Generated with Claude Code