Unit
src/interface/ICloneableV2.sol:11-48 and src/interface/deprecated/ICloneableV1.sol.
Intent oracle
CLAUDE.md describes the current surface:
src/interface/ICloneableFactoryV3.sol — Deterministic-only factory interface (CREATE2, salt namespaced by msg.sender). Standalone — does NOT extend V2; the non-deterministic clone() was intentionally dropped.
src/interface/ICloneableFactoryV4.sol — Current factory interface.
ICloneableFactoryV3 says of V2:
Supersedes ICloneableFactoryV2, whose clone deployed via CREATE (nonce-dependent, only knowable after the fact).
ICloneableV2 is the interface every implementation in the ecosystem is written against, and its NatSpec is normative — it is where MUST ensure that initialize can NOT be called more than once and the success-hash rule live.
Violated property
The normative text of ICloneableV2 points implementers at a superseded factory interface, twice, and the deprecated ICloneableV1 names an interface that does not exist:
ICloneableV2.sol:17-18: "The ICloneableV2 contract is designed to be deployed by an ICloneableFactoryV2 but MUST NOT assume that it will be."
ICloneableV2.sol:40-42: "This avoids false positives where a contract building a proxy, such as an ICloneableFactoryV2, may incorrectly believe that the clone has been initialized…"
deprecated/ICloneableV1.sol:12: "The ICloneableV1 contract is designed to be deployed by an ICloneFactoryV1" — there is no ICloneFactoryV1 in this package or anywhere else; the interface is called ICloneableFactoryV1.
ICloneableV2 is a current, non-deprecated file: it is what LibICloneableFactoryV4 calls and what every cloneable in the ecosystem implements. Nothing in this repo implements ICloneableFactoryV2 — LibICloneableFactoryV4 has no clone at all — so an implementer following ICloneableV2's own text is being pointed at a factory shape this half of the split does not ship. The success-hash rationale in particular reads as if the nonce-dependent V2 factory were the caller, when the actual caller is the V3/V4 cloneDeterministic / cloneDeterministicOpenSalt pair.
Verified repro
Read against c1c2afd:
$ grep -rn "ICloneableFactoryV2" src/interface/ICloneableV2.sol
18: /// be deployed by an `ICloneableFactoryV2` but MUST NOT assume that it
41: /// positives where a contract building a proxy, such as an
42: /// `ICloneableFactoryV2`, may incorrectly believe that the clone has been
$ grep -rn "ICloneFactoryV1" src/
src/interface/deprecated/ICloneableV1.sol:12: /// deployed by an `ICloneFactoryV1` but MUST NOT assume that it will be. It
$ grep -rn "ICloneableFactoryV2" src/lib/
(no matches — the library implements V3/V4 only)
Triage framing
Flagging rather than adjudicating.
The V2 references may be deliberate: ICloneableV2 is versioned against ICloneableFactoryV2 by name and pinning it to "whatever the current factory interface is" would make the interface's text drift every time a factory version lands. If so it is worth saying that explicitly, because as written it reads as staleness rather than as intent.
The ICloneFactoryV1 spelling in the deprecated file looks unambiguously like a typo, but the file is deprecated and published, so whether it is worth touching at all is a maintainer call — this is a comment-only change with no ABI effect.
Found by adversarial review during the AMT campaign on g4-icloneablefactoryv3-newclone.
Unit
src/interface/ICloneableV2.sol:11-48andsrc/interface/deprecated/ICloneableV1.sol.Intent oracle
CLAUDE.mddescribes the current surface:ICloneableFactoryV3says of V2:ICloneableV2is the interface every implementation in the ecosystem is written against, and its NatSpec is normative — it is whereMUST ensure that initialize can NOT be called more than onceand the success-hash rule live.Violated property
The normative text of
ICloneableV2points implementers at a superseded factory interface, twice, and the deprecatedICloneableV1names an interface that does not exist:ICloneableV2.sol:17-18: "TheICloneableV2contract is designed to be deployed by anICloneableFactoryV2but MUST NOT assume that it will be."ICloneableV2.sol:40-42: "This avoids false positives where a contract building a proxy, such as anICloneableFactoryV2, may incorrectly believe that the clone has been initialized…"deprecated/ICloneableV1.sol:12: "TheICloneableV1contract is designed to be deployed by anICloneFactoryV1" — there is noICloneFactoryV1in this package or anywhere else; the interface is calledICloneableFactoryV1.ICloneableV2is a current, non-deprecated file: it is whatLibICloneableFactoryV4calls and what every cloneable in the ecosystem implements. Nothing in this repo implementsICloneableFactoryV2—LibICloneableFactoryV4has nocloneat all — so an implementer followingICloneableV2's own text is being pointed at a factory shape this half of the split does not ship. The success-hash rationale in particular reads as if the nonce-dependent V2 factory were the caller, when the actual caller is the V3/V4cloneDeterministic/cloneDeterministicOpenSaltpair.Verified repro
Read against
c1c2afd:Triage framing
Flagging rather than adjudicating.
The V2 references may be deliberate:
ICloneableV2is versioned againstICloneableFactoryV2by name and pinning it to "whatever the current factory interface is" would make the interface's text drift every time a factory version lands. If so it is worth saying that explicitly, because as written it reads as staleness rather than as intent.The
ICloneFactoryV1spelling in the deprecated file looks unambiguously like a typo, but the file is deprecated and published, so whether it is worth touching at all is a maintainer call — this is a comment-only change with no ABI effect.Found by adversarial review during the AMT campaign on
g4-icloneablefactoryv3-newclone.