Unit
LibICloneableFactoryV4.predictDeterministicAddress (src/lib/LibICloneableFactoryV4.sol:191-197) and the interface text that is its spec: src/interface/ICloneableFactoryV3.sol:16-19 and :58-61.
Intent oracle
Two live interfaces in this repo make claims about cross-network determinism for the same namespaced pair, and they do not agree.
src/interface/ICloneableFactoryV3.sol:16-19:
Cross-network determinism is inherited from the factory: when the factory is itself deployed at the same address on every chain (a Zoltu deterministic deploy), a cloneDeterministic address is identical on every chain for the same caller, implementation and salt.
src/interface/ICloneableFactoryV3.sol:58-61:
A pure function of its inputs and this factory, so it is computable (and pinnable) before deploying, and identical on every chain this factory exists at the same address on.
src/interface/ICloneableFactoryV4.sol:81-90 — writing about both derivations, the namespaced one included:
Cross-network determinism is NOT a property of either derivation on its own. CREATE2 hashes the deploying factory's address, and the EIP-1167 creation code it hashes contains the implementation's address, so an open-salt clone is at the same address on two chains only when BOTH the factory and the implementation are at the same address on both — each deployed deterministically (Zoltu-style), all the way down. Dropping msg.sender from the derivation removes the deployer as a third thing that has to match; it does not make the other two match. If the implementation is deployed by an ordinary nonce-dependent CREATE on each chain, its address differs per chain and so does every clone of it, on both derivations.
Violated property
V4 states the rule correctly and explicitly says it applies "on both derivations". V3 states, for the namespaced derivation, a sufficient condition — factory at the same address — that is not sufficient. The V3 text is the shared spec cloneDeterministic and predictDeterministicAddress are documented against (ICloneableFactoryV4 extends ICloneableFactoryV3 and does not redeclare them), and ICloneableFactoryV3 is a published interface in its own right for "consumers pinned to it" (per CLAUDE.md), so a consumer can reach the wrong claim without ever reading V4.
The ambiguity is in "for the same … implementation". Read as "the same implementation address", V3 is technically true but vacuous — it restates that the function is pure. Read as "the same implementation contract", which is the natural reading for someone reasoning about deploying the same system on two chains, it is false whenever that contract is at different addresses on the two chains, which is the default for a plain CREATE deploy.
Verified repro
Nothing exotic is needed — the implementation address is inside the EIP-1167 creation code that CREATE2 hashes, so two deploys of the same contract land at different addresses and every clone follows:
TestCloneable implA = new TestCloneable();
TestCloneable implB = new TestCloneable(); // identical code, different address
assertEq(address(implA).code, address(implB).code);
assertTrue(address(implA) != address(implB));
// same factory, same caller, same salt
assertTrue(
I_CLONE_FACTORY.predictDeterministicAddress(address(implA), salt, deployer)
!= I_CLONE_FACTORY.predictDeterministicAddress(address(implB), salt, deployer)
);
Two chains where the implementation was deployed by an ordinary nonce-dependent CREATE are exactly this situation: same caller, same salt, same factory address, same implementation contract, different clone address.
Triage framing
Flagging, not adjudicating — this is a documentation-correctness question and the decision is the authors':
- No change needed. "implementation" in V3 already means the address argument, the function is pure in its inputs, and V4 carries the elaboration for anyone who needs it.
- V3 wants correcting. V3 is published standalone for pinned consumers who may never read V4, the phrase "inherited from the factory" actively suggests the factory is the only thing that has to match, and V4 was written specifically to say that it is not. A cross-reference or the same "BOTH the factory and the implementation" qualifier would close it.
No code change is implied either way; predictDeterministicAddress itself is correct and is pinned by the existing suite (mutants swapping address(this), the deployer parameter, and the argument order are all killed).
Found by adversarial review during AMT group g3-libicloneablefactoryv4-clone.
Unit
LibICloneableFactoryV4.predictDeterministicAddress(src/lib/LibICloneableFactoryV4.sol:191-197) and the interface text that is its spec:src/interface/ICloneableFactoryV3.sol:16-19and:58-61.Intent oracle
Two live interfaces in this repo make claims about cross-network determinism for the same namespaced pair, and they do not agree.
src/interface/ICloneableFactoryV3.sol:16-19:src/interface/ICloneableFactoryV3.sol:58-61:src/interface/ICloneableFactoryV4.sol:81-90— writing about both derivations, the namespaced one included:Violated property
V4 states the rule correctly and explicitly says it applies "on both derivations". V3 states, for the namespaced derivation, a sufficient condition — factory at the same address — that is not sufficient. The V3 text is the shared spec
cloneDeterministicandpredictDeterministicAddressare documented against (ICloneableFactoryV4extendsICloneableFactoryV3and does not redeclare them), andICloneableFactoryV3is a published interface in its own right for "consumers pinned to it" (perCLAUDE.md), so a consumer can reach the wrong claim without ever reading V4.The ambiguity is in "for the same … implementation". Read as "the same implementation address", V3 is technically true but vacuous — it restates that the function is pure. Read as "the same implementation contract", which is the natural reading for someone reasoning about deploying the same system on two chains, it is false whenever that contract is at different addresses on the two chains, which is the default for a plain
CREATEdeploy.Verified repro
Nothing exotic is needed — the implementation address is inside the EIP-1167 creation code that
CREATE2hashes, so two deploys of the same contract land at different addresses and every clone follows:Two chains where the implementation was deployed by an ordinary nonce-dependent
CREATEare exactly this situation: same caller, same salt, same factory address, same implementation contract, different clone address.Triage framing
Flagging, not adjudicating — this is a documentation-correctness question and the decision is the authors':
No code change is implied either way;
predictDeterministicAddressitself is correct and is pinned by the existing suite (mutants swappingaddress(this), thedeployerparameter, and the argument order are all killed).Found by adversarial review during AMT group
g3-libicloneablefactoryv4-clone.