Skip to content
Open
85 changes: 57 additions & 28 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,42 +1,71 @@
LibICloneableFactoryV4CheckImplementationCodeTest:testCheckImplementationCodeContract() (gas: 248218)
LibICloneableFactoryV4CheckImplementationCodeTest:testCheckImplementationCodeEtched(address,bytes) (runs: 2048, μ: 7528, ~: 7527)
LibICloneableFactoryV4CheckImplementationCodeTest:testCheckImplementationCodeZero(address) (runs: 2048, μ: 7214, ~: 7267)
ICloneableFactoryV1DeclarationTest:testICloneableFactoryV1AbiPinned() (gas: 10518)
ICloneableFactoryV2DeclarationTest:testAbiPinned() (gas: 10466)
ICloneableFactoryV2DeclarationTest:testCloneSelectorPinned() (gas: 290)
ICloneableFactoryV2DeclarationTest:testNewCloneTopicRelationshipsAcrossTheFamily() (gas: 270)
ICloneableFactoryV2DeclarationTest:testNewCloneTopicZeroPinned() (gas: 267)
ICloneableFactoryV3DeclarationTest:testFunctionAbiPinned() (gas: 15955)
ICloneableFactoryV3DeclarationTest:testFunctionSelectorsPinned() (gas: 325)
ICloneableFactoryV3DeclarationTest:testNewCloneAbiPinned() (gas: 13998)
ICloneableFactoryV3DeclarationTest:testNewCloneNameIsSharedAcrossTheInterfaceFamily() (gas: 313)
ICloneableFactoryV3DeclarationTest:testNewCloneSharedByBothEntryPoints(bytes32,bytes) (runs: 2048, μ: 1001856, ~: 980796)
ICloneableFactoryV3DeclarationTest:testNewCloneTopicZeroPinned() (gas: 245)
ICloneableV1DeclarationTest:testICloneableV1AbiPinned() (gas: 8110)
ICloneableV2InitializeTest:testAbiPinned() (gas: 11499)
ICloneableV2InitializeTest:testInitializeOnlyOnce(bytes32,bytes,bytes) (runs: 2048, μ: 436859, ~: 426854)
ICloneableV2InitializeTest:testInitializeRevertBubblesVerbatim(bytes32,bytes) (runs: 2048, μ: 186098, ~: 185874)
ICloneableV2InitializeTest:testInitializeSelectorPinned() (gas: 245)
ICloneableV2InitializeTest:testInitializeSelectorSharedWithV1() (gas: 267)
ICloneableV2InitializeTest:testInitializeSignatureFnSelectorPinned() (gas: 290)
ICloneableV2InitializeTest:testNothingCalledBeforeInitialize(bytes32,bytes) (runs: 2048, μ: 514544, ~: 503844)
ICloneableV2InitializeTest:testSuccessSentinelPinned() (gas: 289)
ICloneableV2InitializeTest:testTypedOverloadRevertsInitializeSignatureFn(bytes32,bytes,uint256) (runs: 2048, μ: 431755, ~: 421429)
ICloneableV2InitializeTest:testV1ShapedImplementationIsRejected(bytes32,bytes) (runs: 2048, μ: 352503, ~: 342027)
IFactoryDeclarationTest:testIFactoryAbiPinned() (gas: 14451)
LibICloneableFactoryV4CheckImplementationCodeTest:testCheckImplementationCodeContract() (gas: 297955)
LibICloneableFactoryV4CheckImplementationCodeTest:testCheckImplementationCodeEip7702Designator(address,address) (runs: 2048, μ: 7422, ~: 7422)
LibICloneableFactoryV4CheckImplementationCodeTest:testCheckImplementationCodeEtched(address,bytes) (runs: 2048, μ: 7963, ~: 7960)
LibICloneableFactoryV4CheckImplementationCodeTest:testCheckImplementationCodeZero(address) (runs: 2048, μ: 7169, ~: 7223)
LibICloneableFactoryV4CloneCreationCodeTest:testCloneCreationCodeDeploysEIP1167Runtime(address,bytes32) (runs: 2048, μ: 45636, ~: 45636)
LibICloneableFactoryV4CloneCreationCodeTest:testCloneCreationCodeIsEIP1167(address) (runs: 2048, μ: 4245, ~: 4245)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltCallerIndependent(bytes32,bytes,address,address) (runs: 2048, μ: 459061, ~: 443058)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDataInDerivation(bytes32,bytes,bytes) (runs: 2048, μ: 466856, ~: 450600)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDiffersFromSenderNamespaced(address,bytes,bytes32,bytes32,address) (runs: 2048, μ: 8139, ~: 8126)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDisjointTagsCloseTheSquat(address,bytes,bytes) (runs: 2048, μ: 467536, ~: 451203)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDoesNotConsumeNamespacedSalt(bytes32,bytes) (runs: 2048, μ: 456513, ~: 438428)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltEvent(bytes32,bytes) (runs: 2048, μ: 359037, ~: 349969)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltCallerIndependent(bytes32,bytes,address,address) (runs: 2048, μ: 556515, ~: 537270)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDataInDerivation(bytes32,bytes,bytes) (runs: 2048, μ: 563780, ~: 544860)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDiffersFromSenderNamespaced(address,bytes,bytes32,bytes32,address) (runs: 2048, μ: 8141, ~: 8126)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDisjointTagsCloseTheSquat(address,bytes,bytes) (runs: 2048, μ: 564025, ~: 545415)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltDoesNotConsumeNamespacedSalt(bytes32,bytes) (runs: 2048, μ: 553592, ~: 532640)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltEvent(bytes32,bytes) (runs: 2048, μ: 432410, ~: 421907)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltInitializeFailureFails(bytes32,bytes32) (runs: 2048, μ: 167203, ~: 167203)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltIsDomainTaggedHash(address,bytes,bytes32) (runs: 2048, μ: 6499, ~: 6482)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltManyClonesPerImpl(bytes32,bytes32,bytes) (runs: 2048, μ: 455295, ~: 438862)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltMatchesPredict(bytes32,bytes) (runs: 2048, μ: 361663, ~: 352503)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltPredictCallerIndependent(address,bytes,bytes32,address,address) (runs: 2048, μ: 12247, ~: 12224)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltSecondDeployReverts(bytes32,bytes,address,address) (runs: 2048, μ: 1040442913, ~: 1040443151)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltZeroImplementationCodeSize(address,bytes,bytes32) (runs: 2048, μ: 11124, ~: 11129)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicDataNotInDerivation(bytes32,bytes,bytes) (runs: 2048, μ: 464734, ~: 448450)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicEvent(bytes32,bytes) (runs: 2048, μ: 359015, ~: 349951)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltIsDomainTaggedHash(address,bytes,bytes32) (runs: 2048, μ: 6501, ~: 6482)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltManyClonesPerImpl(bytes32,bytes32,bytes) (runs: 2048, μ: 553403, ~: 533074)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltMatchesPredict(bytes32,bytes) (runs: 2048, μ: 435093, ~: 424488)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltPredictCallerIndependent(address,bytes,bytes32,address,address) (runs: 2048, μ: 12248, ~: 12224)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltSecondDeployReverts(bytes32,bytes,address,address) (runs: 2048, μ: 1040445177, ~: 1040445384)
LibICloneableFactoryV4CloneDeterministicOpenSaltTest:testCloneDeterministicOpenSaltZeroImplementationCodeSize(address,bytes,bytes32) (runs: 2048, μ: 11113, ~: 11129)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicDataNotInDerivation(bytes32,bytes,bytes) (runs: 2048, μ: 561623, ~: 542710)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicEvent(bytes32,bytes) (runs: 2048, μ: 432388, ~: 421889)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicInitializeFailureFails(bytes32,bytes32) (runs: 2048, μ: 166695, ~: 166695)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicManyClonesPerImpl(bytes32,bytes32,bytes) (runs: 2048, μ: 455229, ~: 438823)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicMatchesPredict(bytes32,bytes) (runs: 2048, μ: 361175, ~: 352030)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicManyClonesPerImpl(bytes32,bytes32,bytes) (runs: 2048, μ: 553402, ~: 533035)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicMatchesPredict(bytes32,bytes) (runs: 2048, μ: 434604, ~: 424015)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicSaltIsDomainTaggedHash(address,bytes32,address) (runs: 2048, μ: 5563, ~: 5563)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicSecondDeployReverts(bytes32,bytes) (runs: 2048, μ: 1040443447, ~: 1040443612)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicSenderScoped(bytes32,bytes,address,address) (runs: 2048, μ: 459986, ~: 444001)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicZeroImplementationCodeSize(address,bytes,bytes32) (runs: 2048, μ: 11086, ~: 11111)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicSecondDeployReverts(bytes32,bytes) (runs: 2048, μ: 1040445709, ~: 1040445875)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicSenderScoped(bytes32,bytes,address,address) (runs: 2048, μ: 557614, ~: 538213)
LibICloneableFactoryV4CloneDeterministicTest:testCloneDeterministicZeroImplementationCodeSize(address,bytes,bytes32) (runs: 2048, μ: 11088, ~: 11111)
LibICloneableFactoryV4PredictCloneAddressTest:testPredictCloneAddressIsCreate2Formula(address,address,bytes32) (runs: 2048, μ: 1724, ~: 1724)
LibICloneableFactoryV4PredictCloneAddressTest:testPredictCloneAddressMatchesOZ(address,address,bytes32) (runs: 2048, μ: 1570, ~: 1570)
LibICloneableFactoryV4PredictCloneAddressTest:testPredictCloneAddressMatchesRealDeploy(address,bytes32) (runs: 2048, μ: 42869, ~: 42869)
LibICloneableFactoryV4Test:testDerivationsDisjoint(address,bytes32,bytes32,bytes) (runs: 2048, μ: 1405, ~: 1398)
LibICloneableFactoryV4Test:testDerivationsDisjoint(address,bytes32,bytes32,bytes) (runs: 2048, μ: 1406, ~: 1398)
LibICloneableFactoryV4Test:testDomainTagsDistinct() (gas: 233)
LibICloneableFactoryV4Test:testDomainTagsPinned() (gas: 325)
LibICloneableFactoryV4Test:testEffectiveOpenSaltDataSensitive(bytes32,bytes,bytes) (runs: 2048, μ: 4687, ~: 4682)
LibICloneableFactoryV4Test:testEffectiveOpenSaltDataSensitive(bytes32,bytes,bytes) (runs: 2048, μ: 4688, ~: 4682)
LibICloneableFactoryV4Test:testEffectiveOpenSaltEmptyData(bytes32) (runs: 2048, μ: 826, ~: 826)
LibICloneableFactoryV4Test:testEffectiveOpenSaltMatchesFormula(bytes32,bytes) (runs: 2048, μ: 1269, ~: 1257)
LibICloneableFactoryV4Test:testEffectiveOpenSaltPreimageShape(bytes32,bytes) (runs: 2048, μ: 1360, ~: 1348)
LibICloneableFactoryV4Test:testEffectiveOpenSaltSaltSensitive(bytes32,bytes32,bytes) (runs: 2048, μ: 4177, ~: 4166)
LibICloneableFactoryV4Test:testEffectiveOpenSaltMatchesFormula(bytes32,bytes) (runs: 2048, μ: 1270, ~: 1257)
LibICloneableFactoryV4Test:testEffectiveOpenSaltPreimageShape(bytes32,bytes) (runs: 2048, μ: 1361, ~: 1348)
LibICloneableFactoryV4Test:testEffectiveOpenSaltSaltSensitive(bytes32,bytes32,bytes) (runs: 2048, μ: 4179, ~: 4166)
LibICloneableFactoryV4Test:testEffectiveSaltDeployerSensitive(address,address,bytes32) (runs: 2048, μ: 3858, ~: 3858)
LibICloneableFactoryV4Test:testEffectiveSaltMatchesFormula(address,bytes32) (runs: 2048, μ: 865, ~: 865)
LibICloneableFactoryV4Test:testEffectiveSaltPreimageShape(address,bytes32) (runs: 2048, μ: 966, ~: 966)
LibICloneableFactoryV4Test:testEffectiveSaltSaltSensitive(address,bytes32,bytes32) (runs: 2048, μ: 3819, ~: 3819)
LibICloneableFactoryV4Test:testEffectiveSaltSaltSensitive(address,bytes32,bytes32) (runs: 2048, μ: 3819, ~: 3819)
TestCloneFactoryTest:testCloneEntryPointsRouteToTheirOwnDerivation(bytes32,bytes) (runs: 2048, μ: 553292, ~: 532270)
TestCloneFactoryTest:testImplementsICloneableFactoryV4() (gas: 306)
TestCloneFactoryTest:testPredictDeterministicAddressIsPureDelegation(address,bytes32,address) (runs: 2048, μ: 6132, ~: 6132)
TestCloneFactoryTest:testPredictDeterministicAddressOpenSaltIsPureDelegation(address,bytes,bytes32) (runs: 2048, μ: 7039, ~: 7020)
TestCloneFactoryTest:testPredictionsAreStatic(address,bytes,bytes32,address) (runs: 2048, μ: 13621, ~: 13590)
8 changes: 8 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ cbor_metadata = false

libs = ["dependencies"]

# The interface half of this repo is a PUBLISHED ABI: downstream indexers and
# soldeer consumers decode `NewClone` and call `initialize` by NAME, from the
# compiled ABI. Parameter names, parameter order among same-typed parameters,
# `indexed` flags and return types are all invisible to the EVM but visible to
# those consumers, so the only place they can be pinned by a test is the
# compiled artifact. Read-only access to `out` exists for exactly that.
fs_permissions = [{ access = "read", path = "./out" }]

[fuzz]
runs = 2048

Expand Down
123 changes: 123 additions & 0 deletions test/concrete/TestCloneFactory.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

import {Test} from "forge-std-1.16.1/src/Test.sol";

import {ICloneableFactoryV4} from "src/interface/ICloneableFactoryV4.sol";
import {LibICloneableFactoryV4} from "src/lib/LibICloneableFactoryV4.sol";
import {TestCloneFactory} from "test/concrete/TestCloneFactory.sol";
import {TestCloneable} from "test/concrete/TestCloneable.sol";

/// @title TestCloneFactoryTest
/// @notice `TestCloneFactory` is the executable stand-in for the real
/// `CloneFactory` in rain.factory.deploy, and the claim it exists to prove is
/// STRUCTURAL: the library surface suffices for a concrete that adds no
/// behaviour of its own. The 22 flow tests use it as a means to reach the
/// library; nothing asserted the delegation property itself, so a concrete
/// that quietly added behaviour — or that transposed two same-typed arguments
/// on the way through — would still have looked fine.
///
/// This pins it: each of the four entry points equals the library function it
/// claims to be, computed independently here, and the two predictions really
/// are `view`.
contract TestCloneFactoryTest is Test {
/// The `TestCloneFactory` instance under test. Stateless, so reused
/// everywhere.
TestCloneFactory internal immutable I_CLONE_FACTORY;

constructor() {
I_CLONE_FACTORY = new TestCloneFactory();
}

/// The concrete is an `ICloneableFactoryV4`, and therefore also carries
/// `ICloneableFactoryV3`'s two functions. Asserted as a real cast rather
/// than left to the inheritance list.
function testImplementsICloneableFactoryV4() external view {
ICloneableFactoryV4 factory = ICloneableFactoryV4(address(I_CLONE_FACTORY));
assertEq(address(factory), address(I_CLONE_FACTORY));
}

/// `predictDeterministicAddress` is the library function, argument for
/// argument. `implementation` and `deployer` are both `address` and sit in
/// different positions, so transposing them would compile silently; fuzzing
/// them independently is what makes this discriminating.
function testPredictDeterministicAddressIsPureDelegation(address implementation, bytes32 salt, address deployer)
external
view
{
assertEq(
I_CLONE_FACTORY.predictDeterministicAddress(implementation, salt, deployer),
LibICloneableFactoryV4.predictCloneAddress(
address(I_CLONE_FACTORY), implementation, LibICloneableFactoryV4.effectiveSalt(deployer, salt)
)
);
}

/// `predictDeterministicAddressOpenSalt` is the library function, argument
/// for argument.
function testPredictDeterministicAddressOpenSaltIsPureDelegation(
address implementation,
bytes memory data,
bytes32 salt
) external view {
assertEq(
I_CLONE_FACTORY.predictDeterministicAddressOpenSalt(implementation, data, salt),
LibICloneableFactoryV4.predictCloneAddress(
address(I_CLONE_FACTORY), implementation, LibICloneableFactoryV4.effectiveOpenSalt(salt, data)
)
);
}

/// Both predictions are `external view` as the interface declares: a
/// `staticcall` to each succeeds and returns the same answer the ordinary
/// call does. A concrete that widened either to `nonpayable` — adding
/// behaviour the interface forbids — would fail the staticcall.
function testPredictionsAreStatic(address implementation, bytes memory data, bytes32 salt, address deployer)
external
view
{
(bool okNamespaced, bytes memory namespaced) = address(I_CLONE_FACTORY)
.staticcall(abi.encodeCall(I_CLONE_FACTORY.predictDeterministicAddress, (implementation, salt, deployer)));
assertTrue(okNamespaced, "predictDeterministicAddress is not static");
assertEq(
abi.decode(namespaced, (address)),
I_CLONE_FACTORY.predictDeterministicAddress(implementation, salt, deployer)
);

(bool okOpen, bytes memory open) = address(I_CLONE_FACTORY)
.staticcall(
abi.encodeCall(I_CLONE_FACTORY.predictDeterministicAddressOpenSalt, (implementation, data, salt))
);
assertTrue(okOpen, "predictDeterministicAddressOpenSalt is not static");
assertEq(
abi.decode(open, (address)), I_CLONE_FACTORY.predictDeterministicAddressOpenSalt(implementation, data, salt)
);
}

/// The two deploying entry points route to the two DIFFERENT library
/// derivations, each landing where that derivation says and nowhere else.
/// Together with the prediction tests this covers all four delegations and
/// pins that none of them is wired to the other's derivation.
function testCloneEntryPointsRouteToTheirOwnDerivation(bytes32 salt, bytes memory data) external {
TestCloneable implementation = new TestCloneable();

address namespaced = I_CLONE_FACTORY.cloneDeterministic(address(implementation), data, salt);
address open = I_CLONE_FACTORY.cloneDeterministicOpenSalt(address(implementation), data, salt);

assertEq(
namespaced,
LibICloneableFactoryV4.predictCloneAddress(
address(I_CLONE_FACTORY),
address(implementation),
LibICloneableFactoryV4.effectiveSalt(address(this), salt)
)
);
assertEq(
open,
LibICloneableFactoryV4.predictCloneAddress(
address(I_CLONE_FACTORY), address(implementation), LibICloneableFactoryV4.effectiveOpenSalt(salt, data)
)
);
}
}
Loading
Loading