Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
62 changes: 44 additions & 18 deletions src/concrete/CloneFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pragma solidity =0.8.25;

import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "../interface/ICloneableV2.sol";
import {ICloneableFactoryV2} from "../interface/ICloneableFactoryV2.sol";
import {ICloneableFactoryV3} from "../interface/ICloneableFactoryV3.sol";
import {Clones} from "@openzeppelin-contracts-5.6.1/proxy/Clones.sol";

/// Thrown when an implementation has zero code size which is always a mistake.
Expand All @@ -13,28 +13,54 @@ error ZeroImplementationCodeSize();
error InitializationFailed();

/// @title CloneFactory
/// @notice A fairly minimal implementation of `ICloneableFactoryV2`
/// that uses Open Zeppelin `Clones` to create EIP1167 clones of a reference
/// bytecode. The reference bytecode MUST implement `ICloneableV2`.
contract CloneFactory is ICloneableFactoryV2 {
/// @inheritdoc ICloneableFactoryV2
function clone(address implementation, bytes calldata data) external returns (address) {
// Explicitly check that the implementation has code. This is a common
// mistake that will cause the clone to fail. Notably this catches the
// case of address(0). This check is not strictly necessary as a zero
// sized implementation will fail to initialize the child, but it gives
// a better error message.
/// @notice A fairly minimal implementation of `ICloneableFactoryV3` that uses
/// Open Zeppelin `Clones` to create EIP1167 clones of a reference bytecode. The
/// reference bytecode MUST implement `ICloneableV2`.
///
/// `cloneDeterministic` deploys via `CREATE2` at a pre-computable address
/// (`predictDeterministicAddress`), namespacing the caller-supplied salt by
/// `msg.sender` so a caller's `(implementation, salt)` address cannot be squatted
/// by another account.
contract CloneFactory is ICloneableFactoryV3 {
/// @inheritdoc ICloneableFactoryV3
function cloneDeterministic(address implementation, bytes calldata data, bytes32 salt) external returns (address) {
_requireImplementationCode(implementation);
// CREATE2 clone at a salt namespaced by the caller (see `_effectiveSalt`).
address child = Clones.cloneDeterministic(implementation, _effectiveSalt(msg.sender, salt));
return _initializeClone(implementation, child, data);
}

/// @inheritdoc ICloneableFactoryV3
function predictDeterministicAddress(address implementation, bytes32 salt, address deployer)
external
view
returns (address)
{
return Clones.predictDeterministicAddress(implementation, _effectiveSalt(deployer, salt), address(this));
}

/// @dev The CREATE2 salt actually used: the caller-supplied `salt` namespaced
/// by the deploying account. Prevents a caller's `(implementation, salt)`
/// address being front-run/squatted by another account, while still letting a
/// single caller mint many clones of one implementation via distinct salts.
function _effectiveSalt(address deployer, bytes32 salt) internal pure returns (bytes32) {
return keccak256(abi.encode(deployer, salt));
}

/// @dev Reverts with a clear error if `implementation` has no code.
function _requireImplementationCode(address implementation) internal view {
if (implementation.code.length == 0) {
revert ZeroImplementationCodeSize();
}
// Standard Open Zeppelin clone here.
address child = Clones.clone(implementation);
// NewClone does NOT include the data passed to initialize.
// The implementation is responsible for emitting a data event if it
// wants.
}

/// @dev Emit `NewClone` and run the mandatory `ICloneableV2.initialize` check.
/// `NewClone` does NOT include the `data` passed to initialize; the
/// implementation is responsible for emitting a data event if it wants.
function _initializeClone(address implementation, address child, bytes calldata data) internal returns (address) {
emit NewClone(msg.sender, implementation, child);
// Checking the return value of initialize is mandatory as per
// ICloneableFactoryV2.
// ICloneableFactoryV3.
if (ICloneableV2(child).initialize(data) != ICLONEABLE_V2_SUCCESS) {
revert InitializationFailed();
}
Comment thread
thedavidmeister marked this conversation as resolved.
Outdated
Expand Down
8 changes: 4 additions & 4 deletions src/generated/0_1_4/CloneFactory.pointers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ pragma solidity ^0.8.25;
// file needs the contract to exist so that it can be compiled.

/// @dev Hash of the known bytecode.
bytes32 constant BYTECODE_HASH = bytes32(0xf21b813c7075a1621285df3a8369d0652c31ea80cb807be1aaadafeecd134475);
bytes32 constant BYTECODE_HASH = bytes32(0xbcf789fe975f2691258a078e93bf09d1961bf938d70c57912407aa55ef7b4663);

/// @dev The deterministic deploy address of the contract when deployed via
/// the Zoltu factory.
address constant DEPLOYED_ADDRESS = address(0x444acC29d63fa643E8adCC35FD9aa6DE111dCb39);
address constant DEPLOYED_ADDRESS = address(0x4fd3d43755707bf0a571d5F97A17a96b74B07002);

/// @dev The creation bytecode of the contract.
bytes constant CREATION_CODE =
hex"6080604052348015600e575f80fd5b506103f48061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630fbe133c1461002d575b5f80fd5b61004061003b3660046102fb565b610069565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b5f8373ffffffffffffffffffffffffffffffffffffffff163b5f036100ba576040517ff432283200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6100c485610213565b6040805133815273ffffffffffffffffffffffffffffffffffffffff888116602083015283168183015290519192507f274b5f356634f32a865af65bdc3d8205939d9413d75e1f367652e4f3b24d0c3a919081900360600190a16040517f439fab910000000000000000000000000000000000000000000000000000000081527fe0e57eda3f08f2a93bbe980d3df7f9c315eac41181f58b865a13d917fe769fc39073ffffffffffffffffffffffffffffffffffffffff83169063439fab91906101949088908890600401610391565b6020604051808303815f875af11580156101b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101d491906103dd565b1461020b576040517f19b991a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b5f61021e825f610224565b92915050565b5f8147101561026c576040517fcf4791810000000000000000000000000000000000000000000000000000000081524760048201526024810183905260440160405180910390fd5b763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c175f526e5af43d82803e903d91602b57fd5bf38360781b176020526037600983f0905073ffffffffffffffffffffffffffffffffffffffff811661021e576040517fb06ebf3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f6040848603121561030d575f80fd5b833573ffffffffffffffffffffffffffffffffffffffff81168114610330575f80fd5b9250602084013567ffffffffffffffff8082111561034c575f80fd5b818601915086601f83011261035f575f80fd5b81358181111561036d575f80fd5b87602082850101111561037e575f80fd5b6020830194508093505050509250925092565b60208152816020820152818360408301375f818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b5f602082840312156103ed575f80fd5b505191905056";
hex"6080604052348015600e575f80fd5b5061054d8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c806340419eec1461003857806393a7e71114610074575b5f80fd5b61004b61004636600461042f565b610087565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61004b6100823660046104b1565b6100e0565b5f61009185610181565b6040805133602080830191909152818301859052825180830384018152606090920190925280519101205f906100c89087906101d4565b90506100d6868287876101e0565b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff838116602080840191909152828401869052835180840385018152606084019485905280519101203060988401526f5af43d82803e903d91602b57fd5bf3ff608484015260748301879052733d602d80600a3d3981f3363d3d373d3d3d363d7390935260b88201929092526037606c82012060d8820152605560a390910120165b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff163b5f036101d1576040517ff432283200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b5f61017a83835f61032f565b6040805133815273ffffffffffffffffffffffffffffffffffffffff868116602083015285168183015290515f917f274b5f356634f32a865af65bdc3d8205939d9413d75e1f367652e4f3b24d0c3a919081900360600190a16040517f439fab910000000000000000000000000000000000000000000000000000000081527fe0e57eda3f08f2a93bbe980d3df7f9c315eac41181f58b865a13d917fe769fc39073ffffffffffffffffffffffffffffffffffffffff86169063439fab91906102af90879087906004016104ea565b6020604051808303815f875af11580156102cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ef9190610536565b14610326576040517f19b991a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50919392505050565b5f81471015610377576040517fcf4791810000000000000000000000000000000000000000000000000000000081524760048201526024810183905260440160405180910390fd5b763d602d80600a3d3981f3363d3d373d3d3d363d730000008460601b60e81c175f526e5af43d82803e903d91602b57fd5bf38460781b17602052826037600984f5905073ffffffffffffffffffffffffffffffffffffffff811661017a576040517fb06ebf3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461042a575f80fd5b919050565b5f805f8060608587031215610442575f80fd5b61044b85610407565b9350602085013567ffffffffffffffff80821115610467575f80fd5b818701915087601f83011261047a575f80fd5b813581811115610488575f80fd5b886020828501011115610499575f80fd5b95986020929092019750949560400135945092505050565b5f805f606084860312156104c3575f80fd5b6104cc84610407565b9250602084013591506104e160408501610407565b90509250925092565b60208152816020820152818360408301375f818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b5f60208284031215610546575f80fd5b505191905056";

/// @dev The runtime bytecode of the contract.
bytes constant RUNTIME_CODE =
hex"608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630fbe133c1461002d575b5f80fd5b61004061003b3660046102fb565b610069565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b5f8373ffffffffffffffffffffffffffffffffffffffff163b5f036100ba576040517ff432283200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6100c485610213565b6040805133815273ffffffffffffffffffffffffffffffffffffffff888116602083015283168183015290519192507f274b5f356634f32a865af65bdc3d8205939d9413d75e1f367652e4f3b24d0c3a919081900360600190a16040517f439fab910000000000000000000000000000000000000000000000000000000081527fe0e57eda3f08f2a93bbe980d3df7f9c315eac41181f58b865a13d917fe769fc39073ffffffffffffffffffffffffffffffffffffffff83169063439fab91906101949088908890600401610391565b6020604051808303815f875af11580156101b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101d491906103dd565b1461020b576040517f19b991a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b5f61021e825f610224565b92915050565b5f8147101561026c576040517fcf4791810000000000000000000000000000000000000000000000000000000081524760048201526024810183905260440160405180910390fd5b763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c175f526e5af43d82803e903d91602b57fd5bf38360781b176020526037600983f0905073ffffffffffffffffffffffffffffffffffffffff811661021e576040517fb06ebf3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f6040848603121561030d575f80fd5b833573ffffffffffffffffffffffffffffffffffffffff81168114610330575f80fd5b9250602084013567ffffffffffffffff8082111561034c575f80fd5b818601915086601f83011261035f575f80fd5b81358181111561036d575f80fd5b87602082850101111561037e575f80fd5b6020830194508093505050509250925092565b60208152816020820152818360408301375f818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b5f602082840312156103ed575f80fd5b505191905056";
hex"608060405234801561000f575f80fd5b5060043610610034575f3560e01c806340419eec1461003857806393a7e71114610074575b5f80fd5b61004b61004636600461042f565b610087565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61004b6100823660046104b1565b6100e0565b5f61009185610181565b6040805133602080830191909152818301859052825180830384018152606090920190925280519101205f906100c89087906101d4565b90506100d6868287876101e0565b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff838116602080840191909152828401869052835180840385018152606084019485905280519101203060988401526f5af43d82803e903d91602b57fd5bf3ff608484015260748301879052733d602d80600a3d3981f3363d3d373d3d3d363d7390935260b88201929092526037606c82012060d8820152605560a390910120165b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff163b5f036101d1576040517ff432283200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b5f61017a83835f61032f565b6040805133815273ffffffffffffffffffffffffffffffffffffffff868116602083015285168183015290515f917f274b5f356634f32a865af65bdc3d8205939d9413d75e1f367652e4f3b24d0c3a919081900360600190a16040517f439fab910000000000000000000000000000000000000000000000000000000081527fe0e57eda3f08f2a93bbe980d3df7f9c315eac41181f58b865a13d917fe769fc39073ffffffffffffffffffffffffffffffffffffffff86169063439fab91906102af90879087906004016104ea565b6020604051808303815f875af11580156102cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ef9190610536565b14610326576040517f19b991a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50919392505050565b5f81471015610377576040517fcf4791810000000000000000000000000000000000000000000000000000000081524760048201526024810183905260440160405180910390fd5b763d602d80600a3d3981f3363d3d373d3d3d363d730000008460601b60e81c175f526e5af43d82803e903d91602b57fd5bf38460781b17602052826037600984f5905073ffffffffffffffffffffffffffffffffffffffff811661017a576040517fb06ebf3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461042a575f80fd5b919050565b5f805f8060608587031215610442575f80fd5b61044b85610407565b9350602085013567ffffffffffffffff80821115610467575f80fd5b818701915087601f83011261047a575f80fd5b813581811115610488575f80fd5b886020828501011115610499575f80fd5b95986020929092019750949560400135945092505050565b5f805f606084860312156104c3575f80fd5b6104cc84610407565b9250602084013591506104e160408501610407565b90509250925092565b60208152816020820152818360408301375f818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b5f60208284031215610546575f80fd5b505191905056";
58 changes: 58 additions & 0 deletions src/interface/ICloneableFactoryV3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity ^0.8.18;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/// @title ICloneableFactoryV3
/// @notice Creates EIP-1167 proxy clones of a reference bytecode at a
/// deterministic, pre-computable address, and emits events so indexers can
/// discover them. Supersedes `ICloneableFactoryV2`, whose `clone` deployed via
/// `CREATE` (nonce-dependent, only knowable after the fact); this interface
/// deploys exclusively via `CREATE2`, so a clone's address is a pure function of
/// `(implementation, salt, caller, factory)` and can be computed — and pinned —
/// before deploying. It knows nothing about the contracts it clones, relying only
/// on the minimal `ICloneableV2` interface being implemented on the reference
/// bytecode.
///
/// 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.
interface ICloneableFactoryV3 {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
/// Emitted upon each `cloneDeterministic`.
/// @param sender The `msg.sender` that called `cloneDeterministic`.
/// @param implementation The reference bytecode cloned as a proxy.
/// @param clone The address of the new proxy contract.
event NewClone(address sender, address implementation, address clone);

/// Deploys an EIP-1167 proxy clone of `implementation` via `CREATE2`. The
/// factory MUST namespace `salt` by `msg.sender` before deriving the `CREATE2`
/// salt, so a caller's `(implementation, salt)` address cannot be squatted or
/// front-run by another account. Distinct salts from one caller yield distinct
/// clones of the same implementation (many clones per impl).
///
/// The factory MUST call `ICloneableV2.initialize` atomically with the cloning
/// process and MUST NOT call any other functions on the cloned proxy before
/// `initialize` completes successfully. The factory MUST ONLY consider the
/// clone successfully created if `initialize` returns the keccak256 hash of
/// the string "ICloneableV2.initialize". MUST emit `NewClone` with the
/// implementation and clone address.
///
/// @param implementation The contract to clone.
/// @param data As per `ICloneableV2`.
/// @param salt Caller-chosen salt; distinct salts yield distinct clones.
/// @return New child contract address.
function cloneDeterministic(address implementation, bytes calldata data, bytes32 salt) external returns (address);

/// The address `cloneDeterministic(implementation, _, salt)` deploys to when
/// called by `deployer`. 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.
/// @param implementation The contract to clone.
/// @param salt The caller-chosen salt.
/// @param deployer The account that will call `cloneDeterministic`.
/// @return The predicted clone address.
function predictDeterministicAddress(address implementation, bytes32 salt, address deployer)
external
view
returns (address);
}
Loading
Loading