Proxy deployment (UUPS & minimal proxies)
OSx deploys almost everything behind a proxy, so that a cheap-to-deploy front contract delegates to a shared logic contract, and (for UUPS) can be upgraded. ProxyLib is the small library that does both proxy flavors; it's what plugin setups and factories call to instantiate contracts.
solidity
using ProxyLib for address;
// UUPS proxy (ERC-1967): upgradeable in place.
address p = logic.deployUUPSProxy(abi.encodeCall(MyPlugin.initialize, (dao)));
// Minimal proxy (EIP-1167 clone): cheapest, not individually upgradeable.
address c = logic.deployMinimalProxy(abi.encodeCall(MyPlugin.initialize, (dao)));The two map directly onto the plugin types:
- UUPS proxy — an ERC-1967 proxy that runs
_initCalldataagainst the logic during construction. BacksPluginUUPSUpgradeable. Upgradeable (the proxy can point at new logic later). - Minimal proxy (clone) — an ~45-byte EIP-1167 proxy hard-wired to one logic address. Backs
PluginCloneable. Cheapest to deploy, and because that logic address is fixed, a clone's logic can never change. A clone also has no constructor of its own, so, unlike the UUPS proxy above (which initializes during construction), it's initialized by a separate call right after cloning (see below).
ProxyFactory is a thin contract wrapper around the same two functions that additionally emits a ProxyCreated event, useful when you want proxy deployments to be indexable off-chain. Setups can use either the library directly or the factory.
Keep in mind
- A clone has no constructor. EIP-1167 minimal proxies can't run constructor logic, so initialization is a separate call after cloning. Pass
_initCalldataso it happens atomically; an uninitialized proxy is a live-but-unconfigured contract. - Clones are not individually upgradeable. A clone's logic address is fixed forever. "Upgrading" a cloneable plugin means publishing a new version and installing a fresh instance, not changing existing ones.
- UUPS storage discipline. New state in an upgradeable implementation must respect the reserved
__gap(see protocol version); shifting the layout corrupts every existing proxy.
See also
- Choosing a plugin base — which proxy flavor each plugin type uses.
- Plugin setup — the main caller of
ProxyLib. - Protocol version — the storage-gap discipline upgradeable proxies rely on.