Docs at https://rainprotocol.github.io/rain.factory
This repo is the library half of the library/deploy split
(#46): the
ICloneable* interface surface and the LibICloneableFactoryV4 library that
implements it. It publishes to Soldeer as rain-factory.
CloneFactory — the concrete that implements these interfaces, letting any
compatible ICloneableV2 contract be cloned as an EIP1167 proxy and initialized
— lives in
rain.factory.deploy,
together with its deployed address + codehash pins, its frozen per-release
deploy-pin snapshots and its deploy script. That repo publishes as
rain-factory-deploy.
Depend on rain-factory if you need the interfaces or the library. Depend on
rain-factory-deploy if you need the deployed address or codehash of a live
CloneFactory.
src/lib/LibICloneableFactoryV4.sol is the executable form of
ICloneableFactoryV4 as internal library logic. The two CREATE2 salt
derivations the interface pins to exact bytes — the msg.sender-namespaced one
and the open-salt one — are pure functions that import the domain tags from the
interface, so the tags have a single source of truth and a factory, an indexer
or a consumer predicting a clone address computes the salt from one place. On
top of them sit the implementation-code guard, the EIP1167 creation code and its
CREATE2 address prediction (constructed from the standard's own bytes, so the
published src/ depends on no external cloning code), and the atomic
clone-initialize-verify flow with its typed errors and the NewClone event.
msg.sender and address(this) are read inside the library, so a concrete
factory is nothing but one delegation per entry point and cannot misroute
either. The tests live here under test/src/lib/: they recompute both salt
formulas independently to pin them to the interface's spec byte for byte, and
pin the EIP1167 construction against OpenZeppelin Clones as a foreign
implementation of the same standard.
Contains interfaces for working with Rain factories.
Rain tooling/ecosystem generally tries to be as agnostic and low friction as possible on the implementation side.
The ideal would be that "any" contract can call an interpreter and magically be supported but there's a lot that can go wrong, for example:
- Contracts can self-destruct or even be redeployed with new bytecode
- Proxies can point to new implementations and "upgrade"
- Discoverability of ABIs and other metadata subject to indexer limitations
Falling short of the ideal, we want to support:
- Ability to (dis)trust contracts at the bytecode level NOT the human/key level
- Support existing patterns such as EIP1167 for clones, etc.
- Avoid introducing Rain-isms as much as possible
The onchain tooling for analysis is found at https://github.com/rainprotocol/rain.extrospection
The current interfaces in this repository are for
ICloneableFactoryV4, the current factory interface. ExtendsICloneableFactoryV3— nothing was dropped this time, so it inherits rather than restates — and adds a second deterministic derivation,cloneDeterministicOpenSalt+predictDeterministicAddressOpenSalt, whoseCREATE2salt hashes the caller-supplied salt together with the initialization data and nothing about the caller. The two derivations differ in what the clone's address commits to, and neither dominates: the V3 pair namespaces the salt bymsg.sender, so the address commits to WHO deployed and not to WHAT — nobody else can reach the caller's address, but the deploying account is baked into it forever and the deployer alone decides the initial state. The open-salt pair commits to WHAT and not to WHO — every account reaches the same address, and so can anyone, but everyone who reaches it deploys the same contract initialized with the same bytes, because varying either input lands somewhere else. Its cost is that the address is not knowable until the data is final. The residual the address cannot fix — implementations MUST NOT readtx.origin— and the address-registry pairing it is intended for are spelled out in the NatSpec onICloneableFactoryV4.cloneDeterministicOpenSaltICloneableFactoryV3, deterministic-only (cloneDeterministic+predictDeterministicAddress, CREATE2 with the salt namespaced bymsg.sender). Superseded byICloneableFactoryV4, still published for consumers pinned to it. Standalone rather than extendingICloneableFactoryV2, because the non-deterministicclone()was intentionally droppedICloneableFactoryV2that is expected to clone proxies from a reference implementation. Superseded byICloneableFactoryV3for the concrete factory, still published for other consumers- A small interface
ICloneableV2designed for cloneable proxy contracts to expose aninitializefunction that the factory can call to act like a constructor
This version of ICloneable did not have any explicit return value on success
of initialize. It is possible for contracts that do not implement ICloneableV1
to silently fail to initialize when cloned by an ICloneableFactoryV1.
Newer versions of the interface include an explicit success value and check.
The legacy factory model was much more restricted in that each factory implementation was 1:1 with the thing it was deploying. If you needed a new contract you also needed to implement a new factory.
This was suboptimal for several reasons:
- Increased surface area for things to go wrong
- More Rain-isms creeping in
- Redundant work to maintain a growing list of factories
The legacy interface is available as IFactory but it is NOT RECOMMENDED for
new contracts.