Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 13 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,24 @@ forge build
- `src/interface/ICloneableFactoryV2.sol` — Legacy factory interface: the
nonce-dependent `clone(address, bytes)` and `NewClone` event. Superseded by
`ICloneableFactoryV3` for `CloneFactory`; still published for other consumers.
- `src/interface/ICloneableFactoryV3.sol` — Current factory interface.
Deterministic-only: `cloneDeterministic(address, bytes, bytes32)` +
- `src/interface/ICloneableFactoryV3.sol` — Deterministic-only factory
interface: `cloneDeterministic(address, bytes, bytes32)` +
`predictDeterministicAddress(address, bytes32, address)` (CREATE2, salt
namespaced by `msg.sender`) and its own `NewClone` event. Standalone — does
NOT extend `ICloneableFactoryV2`, because the non-deterministic `clone()` was
intentionally dropped.
- `src/interface/ICloneableFactoryV4.sol` — Current factory interface. Extends
`ICloneableFactoryV3` (nothing was dropped, so it inherits rather than
restates) and adds the open-salt variant:
`cloneDeterministicOpenSalt(address, bytes, bytes32)` +
`predictDeterministicAddressOpenSalt(address, bytes32)`, which use the
caller-supplied salt verbatim so the deployer is not in the address
derivation. Only safe for implementations whose `initialize` takes no
caller-controlled authority — the NatSpec on the function is the spec for
that.
- `src/concrete/CloneFactory.sol` — The single concrete implementation of
`ICloneableFactoryV3`. Uses OpenZeppelin `Clones.cloneDeterministic()`; there
is no plain `clone()`.
`ICloneableFactoryV4`. Uses OpenZeppelin `Clones.cloneDeterministic()` for
both variants; there is no plain `clone()`.
- `src/lib/LibCloneFactoryDeploy.sol` — Deterministic deployment address and
codehash constants (generated; aliases the current tag's
`src/generated/<tag>/` snapshot).
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,22 @@ Docs at https://rainprotocol.github.io/rain.factory

## Concrete implementations

`CloneFactory` implements `ICloneableFactoryV2` allowing any
`CloneFactory` implements `ICloneableFactoryV4` allowing any
compatible `ICloneableV2` contract to be cloned as an EIP1167 proxy and
initialized.

It offers two deterministic (`CREATE2`) entry points that differ only in how the
salt is derived:

- `cloneDeterministic` namespaces the caller-supplied salt by `msg.sender`, so
nobody else can reach the caller's address.
- `cloneDeterministicOpenSalt` uses the caller-supplied salt verbatim, so the
address is a function of `(implementation, salt)` and the factory alone —
portable across accounts and chains, but reachable by anyone. It is ONLY safe
for implementations whose `initialize` takes no caller-controlled authority;
read the NatSpec on `ICloneableFactoryV4.cloneDeterministicOpenSalt` before
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
using it.

## Interfaces

Contains interfaces for working with Rain factories.
Expand All @@ -32,8 +44,12 @@ The onchain tooling for analysis is found at https://github.com/rainprotocol/rai

The current interfaces in this repository are for

- `ICloneableFactoryV2` that is expected to clone proxies from a reference
implementation
- `ICloneableFactoryV4` that is expected to clone proxies from a reference
implementation, deterministically, with or without the deployer in the address
derivation. It extends `ICloneableFactoryV3` (deterministic-only, deployer
always in the derivation), which is still published for consumers pinned to it
- `ICloneableFactoryV2` that clones via a nonce-dependent `CREATE`. Superseded
for `CloneFactory`, still published for other consumers
- A small interface `ICloneableV2` designed for cloneable proxy contracts to
expose an `initialize` function that the factory can call to act like a
constructor
Expand Down
42 changes: 35 additions & 7 deletions src/concrete/CloneFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
pragma solidity =0.8.25;

import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "../interface/ICloneableV2.sol";
// `ICloneableFactoryV3` is imported for the `@inheritdoc` references on the
// functions it declares; `ICloneableFactoryV4` inherits rather than redeclares
// them, so the tag must name V3 and V3 must be in scope here.
import {ICloneableFactoryV3} from "../interface/ICloneableFactoryV3.sol";
import {ICloneableFactoryV4} from "../interface/ICloneableFactoryV4.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,15 +17,21 @@ error ZeroImplementationCodeSize();
error InitializationFailed();

/// @title CloneFactory
/// @notice A fairly minimal implementation of `ICloneableFactoryV3` that uses
/// @notice A fairly minimal implementation of `ICloneableFactoryV4` 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 {
/// Two deterministic entry points, both `CREATE2`, differing only in the salt:
///
/// - `cloneDeterministic` / `predictDeterministicAddress` namespace the
/// caller-supplied salt by `msg.sender` (see `_effectiveSalt`) so a caller's
/// `(implementation, salt)` address cannot be squatted by another account.
/// - `cloneDeterministicOpenSalt` / `predictDeterministicAddressOpenSalt` use
/// the caller-supplied salt verbatim, so the address carries no identity and
/// anyone can deploy it. This is only safe for implementations whose
/// `initialize` takes no caller-controlled authority — read the warning on
/// `ICloneableFactoryV4.cloneDeterministicOpenSalt` before using it.
contract CloneFactory is ICloneableFactoryV4 {
/// @inheritdoc ICloneableFactoryV3
function cloneDeterministic(address implementation, bytes calldata data, bytes32 salt) external returns (address) {
_requireImplementationCode(implementation);
Expand All @@ -39,6 +49,24 @@ contract CloneFactory is ICloneableFactoryV3 {
return Clones.predictDeterministicAddress(implementation, _effectiveSalt(deployer, salt), address(this));
}

/// @inheritdoc ICloneableFactoryV4
function cloneDeterministicOpenSalt(address implementation, bytes calldata data, bytes32 salt)
external
returns (address)
{
_requireImplementationCode(implementation);
// CREATE2 clone at the caller-supplied salt verbatim: no `_effectiveSalt`
// namespacing, so the address is the same for every caller and there is
// no identity in the derivation.
address child = Clones.cloneDeterministic(implementation, salt);
return _initializeClone(implementation, child, data, salt);
}

/// @inheritdoc ICloneableFactoryV4
function predictDeterministicAddressOpenSalt(address implementation, bytes32 salt) external view returns (address) {
return Clones.predictDeterministicAddress(implementation, 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
Expand Down Expand Up @@ -69,7 +97,7 @@ contract CloneFactory is ICloneableFactoryV3 {
{
emit NewClone(msg.sender, implementation, child, salt, data);
// Checking the return value of initialize is mandatory as per
// ICloneableFactoryV3.
// ICloneableFactoryV3 and ICloneableFactoryV4.
if (ICloneableV2(child).initialize(data) != ICLONEABLE_V2_SUCCESS) {
revert InitializationFailed();
}
Expand Down
25 changes: 25 additions & 0 deletions src/generated/0_1_6/CloneFactory.pointers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity ^0.8.25;

// THIS FILE IS AUTOGENERATED BY ./script/BuildPointers.sol

// This file is committed to the repository because there is a circular
// dependency between the contract and its pointers file. The contract
// needs the pointers file to exist so that it can compile, and the pointers
// file needs the contract to exist so that it can be compiled.

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

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

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

/// @dev The runtime bytecode of the contract.
bytes constant RUNTIME_CODE =
hex"608060405234801561000f575f80fd5b506004361061004a575f3560e01c806340375cb71461004e57806340419eec1461008a57806393a7e7111461009d578063fc90f455146100b0575b5f80fd5b61006161005c36600461043d565b61012e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61006161009836600461043d565b61015c565b6100616100ab3660046104bf565b610183565b6100616100be3660046104f8565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012073ffffffffffffffffffffffffffffffffffffffff1690565b5f610138856101a5565b5f61014386846101f8565b90506101528682878787610204565b9695505050505050565b5f610166856101a5565b5f6101438661017e33865f9182526020526040902090565b6101f8565b5f61019b846100be84865f9182526020526040902090565b90505b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff163b5f036101f5576040517ff432283200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b5f61019e83835f61033d565b5f7f3b3e5b48cfaf4a4b3b2b36425ddec21c2c507fd502d2aea55eb7ffa36b0ca20533878785888860405161023e96959493929190610567565b60405180910390a16040517f439fab910000000000000000000000000000000000000000000000000000000081527fe0e57eda3f08f2a93bbe980d3df7f9c315eac41181f58b865a13d917fe769fc39073ffffffffffffffffffffffffffffffffffffffff87169063439fab91906102bc90889088906004016105ba565b6020604051808303815f875af11580156102d8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102fc91906105cd565b14610333576040517f19b991a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092949350505050565b5f81471015610385576040517fcf4791810000000000000000000000000000000000000000000000000000000081524760048201526024810183905260440160405180910390fd5b763d602d80600a3d3981f3363d3d373d3d3d363d730000008460601b60e81c175f526e5af43d82803e903d91602b57fd5bf38460781b17602052826037600984f5905073ffffffffffffffffffffffffffffffffffffffff811661019e576040517fb06ebf3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803573ffffffffffffffffffffffffffffffffffffffff81168114610438575f80fd5b919050565b5f805f8060608587031215610450575f80fd5b61045985610415565b9350602085013567ffffffffffffffff80821115610475575f80fd5b818701915087601f830112610488575f80fd5b813581811115610496575f80fd5b8860208285010111156104a7575f80fd5b95986020929092019750949560400135945092505050565b5f805f606084860312156104d1575f80fd5b6104da84610415565b9250602084013591506104ef60408501610415565b90509250925092565b5f8060408385031215610509575f80fd5b61051283610415565b946020939093013593505050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff8089168352808816602084015280871660408401525084606083015260a060808301526105ae60a083018486610520565b98975050505050505050565b602081525f61019b602083018486610520565b5f602082840312156105dd575f80fd5b505191905056";
Loading
Loading