Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
50 changes: 38 additions & 12 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This file provides guidance to Claude Code (claude.ai/code) when working with
code in this repository.

## Project Overview

rain.factory is a Solidity library providing EIP1167 minimal proxy (clone) factory contracts for the Rain ecosystem. The core contract `CloneFactory` clones any contract implementing `ICloneableV2` and atomically initializes it.
rain.factory is a Solidity library providing EIP1167 minimal proxy (clone)
factory contracts for the Rain ecosystem. The core contract `CloneFactory`
clones any contract implementing `ICloneableV2` and atomically initializes it.

License: LicenseRef-DCL-1.0 (Dark Matter Council License). All source files must include SPDX headers.
License: LicenseRef-DCL-1.0 (Dark Matter Council License). All source files must
include SPDX headers.

## Build & Test Commands

Expand Down Expand Up @@ -50,24 +54,46 @@ forge build

## Architecture

- `src/interface/ICloneableV2.sol` — Interface for cloneable contracts. `initialize(bytes)` must return `ICLONEABLE_V2_SUCCESS` (keccak256 hash) on success.
- `src/interface/ICloneableFactoryV2.sol` — Factory interface with `clone(address, bytes)` and `NewClone` event.
- `src/concrete/CloneFactory.sol` — The single concrete implementation. Uses OpenZeppelin `Clones.clone()`.
- `src/lib/LibCloneFactoryDeploy.sol` — Deterministic deployment address and codehash constants.
- `src/interface/deprecated/` — Legacy interfaces (`ICloneableV1`, `ICloneableFactoryV1`, `IFactory`). Do not use for new work.
- `src/interface/ICloneableV2.sol` — Interface for cloneable contracts.
`initialize(bytes)` must return `ICLONEABLE_V2_SUCCESS` (keccak256 hash) on
success.
- `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)` +
`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/concrete/CloneFactory.sol` — The single concrete implementation of
`ICloneableFactoryV3`. Uses OpenZeppelin `Clones.cloneDeterministic()`; 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).
- `src/interface/deprecated/` — Legacy interfaces (`ICloneableV1`,
`ICloneableFactoryV1`, `IFactory`). Do not use for new work.

## Solidity Conventions

- Solidity version: `=0.8.25` (exact, not caret)
- Solidity version: concrete contracts pin `=0.8.25` (exact); interface and
library files float `^` (the interfaces use `^0.8.18`) so downstream soldeer
consumers on a different `0.8.x` can still compile them
- EVM target: Cancun
- Optimizer: enabled, 100,000 runs
- No CBOR metadata (`cbor_metadata = false`, `bytecode_hash = "none"`)
- Dependencies are git submodules in `lib/` (forge-std, openzeppelin-contracts, rain.deploy, rain.extrospection)
- Dependencies are git submodules in `lib/` (forge-std, openzeppelin-contracts,
rain.deploy, rain.extrospection)

## Deployment

Deployed via deterministic Zoltu deployer (from `rain.deploy`). The canonical deployment address and codehash are committed in `LibCloneFactoryDeploy.sol`. Deployment scripts are in `script/Deploy.sol` targeting Arbitrum, Base, Flare, and Polygon.
Deployed via deterministic Zoltu deployer (from `rain.deploy`). The canonical
deployment address and codehash are committed in `LibCloneFactoryDeploy.sol`.
Deployment scripts are in `script/Deploy.sol` targeting Arbitrum, Base, Flare,
and Polygon.

## CI

GitHub Actions runs three parallel jobs on every push: `rainix-sol-test`, `rainix-sol-static`, `rainix-sol-legal`. Fork tests require RPC URL secrets.
GitHub Actions runs three parallel jobs on every push: `rainix-sol-test`,
`rainix-sol-static`, `rainix-sol-legal`. Fork tests require RPC URL secrets.
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";
Loading
Loading