Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions test/abstract/CloneFactoryTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

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

import {TestCloneFactory} from "test/concrete/TestCloneFactory.sol";

/// @title CloneFactoryTest
/// @notice Base for the tests that drive the library through
/// `TestCloneFactory`. Holds the factory instance they all need and the
/// `NewClone` log assertion, so the event signature is written out once.
abstract contract CloneFactoryTest is Test {
/// The `TestCloneFactory` instance under test. Stateless, so reused
/// everywhere.
TestCloneFactory internal immutable I_CLONE_FACTORY;

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

/// Asserts `entry` is the factory's `NewClone` for this deploy: the
/// factory as emitter, the event signature as topic 0, and the five
/// arguments as the data.
/// @param entry The recorded log to check.
/// @param sender The caller the event should name.
/// @param implementation The implementation the clone delegates to.
/// @param clone The deployed clone.
/// @param salt The raw caller salt.
/// @param data The initialization data.
function assertNewClone(
Vm.Log memory entry,
address sender,
address implementation,
address clone,
bytes32 salt,
bytes memory data
) internal view {
assertEq(entry.emitter, address(I_CLONE_FACTORY));
assertEq(entry.topics[0], keccak256("NewClone(address,address,address,bytes32,bytes)"));
assertEq(entry.data, abi.encode(sender, implementation, clone, salt, data));
}
}
14 changes: 2 additions & 12 deletions test/src/interface/ICloneableV2.initialize.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,15 @@
// 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 {ICloneableV2} from "src/interface/ICloneableV2.sol";
import {TestCloneFactory} from "test/concrete/TestCloneFactory.sol";
import {CloneFactoryTest} from "test/abstract/CloneFactoryTest.sol";
import {TestCloneable, TestCloneableAlreadyInitialized} from "test/concrete/TestCloneable.sol";

/// @title ICloneableV2InitializeTest
/// @notice `ICloneableV2`'s two MUSTs on `initialize`, exercised on
/// `TestCloneable` and on clones of it that `TestCloneFactory` deployed and
/// initialized.
contract ICloneableV2InitializeTest is Test {
/// The `TestCloneFactory` instance under test. Stateless, so reused
/// everywhere.
TestCloneFactory internal immutable I_CLONE_FACTORY;

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

contract ICloneableV2InitializeTest is CloneFactoryTest {
/// `initialize` can NOT be called more than once: the factory's call is
/// the one that succeeds, a second call on the clone reverts
/// `TestCloneableAlreadyInitialized`, and the clone keeps the data the
Expand Down
12 changes: 2 additions & 10 deletions test/src/lib/LibICloneableFactoryV4.cloneAndInitialize.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,16 @@
// 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 {ICLONEABLE_V2_SUCCESS} from "src/interface/ICloneableV2.sol";
import {DelegatedImplementation, InitializationFailed} from "src/lib/LibICloneableFactoryV4.sol";
import {TestCloneFactory} from "test/concrete/TestCloneFactory.sol";
import {CloneFactoryTest} from "test/abstract/CloneFactoryTest.sol";
import {TestCloneable} from "test/concrete/TestCloneable.sol";
import {TestCloneableRawAnswer} from "test/concrete/TestCloneableRawAnswer.sol";

/// @title LibICloneableFactoryV4CloneAndInitializeTest
/// @notice How `cloneAndInitialize` guards the implementation and treats each
/// `initialize` answer, through both clone entry points.
contract LibICloneableFactoryV4CloneAndInitializeTest is Test {
TestCloneFactory internal immutable I_CLONE_FACTORY;

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

contract LibICloneableFactoryV4CloneAndInitializeTest is CloneFactoryTest {
/// Both entry points revert with exactly `expected` when `initialize`
/// reverts with (`reverts`) or returns `answer`.
function checkBothEntryPointsRevert(bool reverts, bytes memory answer, bytes32 salt, bytes memory expected)
Expand Down
24 changes: 6 additions & 18 deletions test/src/lib/LibICloneableFactoryV4.cloneDeterministic.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

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

import {Clones} from "@openzeppelin-contracts-5.6.1/proxy/Clones.sol";
import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "src/interface/ICloneableV2.sol";
Expand All @@ -13,7 +13,7 @@ import {
InitializationFailed,
ZeroImplementationCodeSize
} from "src/lib/LibICloneableFactoryV4.sol";
import {TestCloneFactory} from "test/concrete/TestCloneFactory.sol";
import {CloneFactoryTest} from "test/abstract/CloneFactoryTest.sol";
import {TestCloneable} from "test/concrete/TestCloneable.sol";
import {TestCloneableCallRecorder} from "test/concrete/TestCloneableCallRecorder.sol";
import {TestCloneableFailure} from "test/concrete/TestCloneableFailure.sol";
Expand All @@ -26,15 +26,7 @@ import {TestCloneableRevert, TestCloneableRevertInitialize} from "test/concrete/
/// namespacing and the `NewClone` event only exist across an external call.
/// The defining property is that the address commits to WHO deployed —
/// `(deployer, salt)` — and not to WHAT was initialized.
contract LibICloneableFactoryV4CloneDeterministicTest is Test {
/// The `TestCloneFactory` instance under test. Stateless, so reused
/// everywhere.
TestCloneFactory internal immutable I_CLONE_FACTORY;

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

contract LibICloneableFactoryV4CloneDeterministicTest is CloneFactoryTest {
/// The effective `CREATE2` salt is exactly the derivation
/// `ICloneableFactoryV4` fixes:
/// `keccak256(abi.encode(ICLONEABLE_FACTORY_V4_NAMESPACED_DOMAIN, msg.sender, salt))`.
Expand Down Expand Up @@ -186,9 +178,7 @@ contract LibICloneableFactoryV4CloneDeterministicTest is Test {
Vm.Log[] memory entries = vm.getRecordedLogs();

assertEq(entries.length, 1);
assertEq(entries[0].emitter, address(I_CLONE_FACTORY));
assertEq(entries[0].topics[0], bytes32(uint256(keccak256("NewClone(address,address,address,bytes32,bytes)"))));
assertEq(entries[0].data, abi.encode(address(this), address(implementation), child, salt, data));
assertNewClone(entries[0], address(this), address(implementation), child, salt, data);
}

/// An implementation that initializes to a non-success code reverts
Expand Down Expand Up @@ -281,12 +271,10 @@ contract LibICloneableFactoryV4CloneDeterministicTest is Test {

assertEq(entries.length, 2);

assertEq(entries[0].emitter, address(I_CLONE_FACTORY));
assertEq(entries[0].topics[0], bytes32(uint256(keccak256("NewClone(address,address,address,bytes32,bytes)"))));
assertEq(entries[0].data, abi.encode(address(this), address(implementation), child, salt, data));
assertNewClone(entries[0], address(this), address(implementation), child, salt, data);

assertEq(entries[1].emitter, child);
assertEq(entries[1].topics[0], bytes32(uint256(keccak256("Initializing(bytes)"))));
assertEq(entries[1].topics[0], keccak256("Initializing(bytes)"));
assertEq(entries[1].data, abi.encode(data));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

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

import {Clones} from "@openzeppelin-contracts-5.6.1/proxy/Clones.sol";
import {ICLONEABLE_V2_SUCCESS} from "src/interface/ICloneableV2.sol";
Expand All @@ -16,7 +16,7 @@ import {
InitializationFailed,
ZeroImplementationCodeSize
} from "src/lib/LibICloneableFactoryV4.sol";
import {TestCloneFactory} from "test/concrete/TestCloneFactory.sol";
import {CloneFactoryTest} from "test/abstract/CloneFactoryTest.sol";
import {TestCloneable} from "test/concrete/TestCloneable.sol";
import {TestCloneableFailure} from "test/concrete/TestCloneableFailure.sol";

Expand All @@ -29,15 +29,7 @@ import {TestCloneableFailure} from "test/concrete/TestCloneableFailure.sol";
/// guarantees. So the two derivations are also tested against each other here,
/// including the one squat that the pair of distinct domain tags exists to
/// close.
contract LibICloneableFactoryV4CloneDeterministicOpenSaltTest is Test {
/// The `TestCloneFactory` instance under test. Stateless, so reused
/// everywhere.
TestCloneFactory internal immutable I_CLONE_FACTORY;

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

contract LibICloneableFactoryV4CloneDeterministicOpenSaltTest is CloneFactoryTest {
/// The effective `CREATE2` salt is exactly the derivation
/// `ICloneableFactoryV4` fixes:
/// `keccak256(abi.encode(ICLONEABLE_FACTORY_V4_OPEN_SALT_DOMAIN, salt, keccak256(data)))`.
Expand Down Expand Up @@ -363,9 +355,7 @@ contract LibICloneableFactoryV4CloneDeterministicOpenSaltTest is Test {
Vm.Log[] memory entries = vm.getRecordedLogs();

assertEq(entries.length, 1);
assertEq(entries[0].emitter, address(I_CLONE_FACTORY));
assertEq(entries[0].topics[0], bytes32(uint256(keccak256("NewClone(address,address,address,bytes32,bytes)"))));
assertEq(entries[0].data, abi.encode(address(this), address(implementation), child, salt, data));
assertNewClone(entries[0], address(this), address(implementation), child, salt, data);
}

/// An implementation that initializes to a non-success code reverts
Expand Down
Loading