How to upgrade a smart contract?

OpenZeppelin's Proxy Patterns: A Comprehensive Guide

Published on
March 30, 2025
How to upgrade a smart contract?

OpenZeppelin provides several proxy patterns that enable contract upgradeability.

Each pattern has different trade-offs in terms of security, gas efficiency, and complexity.

Here's a rundown of all the major proxy patterns they offer:

1. Transparent Proxy Pattern

This is the original and most battle-tested proxy pattern from OpenZeppelin.

How it works:

  • The proxy delegates all calls to an implementation contract
  • Uses a special mechanism to distinguish between admin functions and regular functions
  • Admin calls go to the proxy, user calls are delegated to the implementation

Key components:

  • TransparentUpgradeableProxy: The main proxy contract
  • ProxyAdmin: A separate contract that owns and manages the proxy

Advantages:

  • Clear separation between admin and user functions
  • Prevents "admin shadowing" issues where proxy admin functions could conflict with implementation functions
  • Well-tested in production environments

Disadvantages:

  • Higher gas costs for regular user functions due to additional checks
  • Requires a separate admin contract

When to use it:

  • When security is the highest priority
  • For high-value applications where gas optimization is less critical

2. UUPS (Universal Upgradeable Proxy Standard)

A more gas-efficient approach that moves the upgrade logic to the implementation contract.

How it works:

  • The proxy contains minimal code and delegates everything
  • Upgrade functionality is in the implementation itself
  • Uses EIP-1822's storage slot approach for upgrades

Key components:

  • ERC1967Proxy: A lightweight proxy
  • UUPSUpgradeable: Contract that implementations inherit from to include upgrade logic

Advantages:

  • More gas efficient for user operations
  • Single storage slot for implementation address
  • Simpler proxy code

Disadvantages:

  • Implementations must include upgrade logic
  • Risk of forgetting to include upgrade functionality in new implementations

When to use it:

  • For gas-sensitive applications
  • When you prefer having all functionality in the implementation

3. Beacon Proxy Pattern

Designed for managing multiple proxies that should all use the same implementation.

How it works:

  • A central "beacon" contract stores the current implementation address
  • Multiple proxies point to this beacon instead of directly to an implementation
  • Upgrading the beacon updates all proxies at once

Key components:

  • BeaconProxy: Proxy that reads implementation from a beacon
  • UpgradeableBeacon: Contract that stores the current implementation address

Advantages:

  • Efficient for managing many proxy instances (like tokens or NFTs)
  • Single upgrade transaction affects all proxies
  • Lower deployment costs for multiple proxies

Disadvantages:

  • Additional layer of indirection (slightly higher gas costs per call)
  • Centralized upgrade point (could be advantage or disadvantage)

When to use it:

  • When deploying many instances that should share the same implementation
  • For NFT or token factory patterns

4. Diamond Proxy Pattern (EIP-2535)

A more complex but powerful pattern for modular contract systems.

How it works:

  • Supports multiple implementation contracts ("facets")
  • Each function selector maps to a specific facet
  • Allows for partial upgrades of functionality

Key components:

  • Diamond: The main proxy contract
  • DiamondCutFacet: Manages adding/replacing/removing facets
  • DiamondLoupeFacet: Provides introspection (examining the current state)

Advantages:

  • Highly modular - can upgrade parts independently
  • No contract size limitations (bypasses the 24KB contract size limit)
  • More granular access control

Disadvantages:

  • Significantly more complex to implement and manage
  • Higher initial deployment costs
  • Steeper learning curve

When to use it:

  • For very large and complex systems
  • When you need to split functionality across multiple contracts
  • When you need extremely fine-grained upgradeability

5. Minimal Proxy (EIP-1167 or "Clones")

Not technically an upgradeable proxy, but worth mentioning:

How it works:

  • Creates extremely cheap copies of a contract
  • All clones delegate to the same implementation
  • Cannot be upgraded individually

Key components:

  • Clones: Library for deploying minimal proxies

Advantages:

  • Extremely gas-efficient deployment (less than 50k gas per clone)
  • Perfect for factory patterns

Disadvantages:

  • Not upgradeable
  • All instances share the same implementation forever

When to use it:

  • When you need many instances of the same contract
  • When upgradeability isn't needed

Choosing the Right Pattern

  • Transparent Proxy: Highest security, standard for critical applications
  • UUPS: Better gas efficiency, good general-purpose choice
  • Beacon: When managing many proxy instances that follow the same implementation
  • Diamond: For complex systems requiring modularity and partial upgrades
  • Minimal Proxy: When upgradeability isn't needed but cheap deployment is

Security Considerations Across All Patterns

  1. Storage layout: Must be preserved across upgrades
  2. Initialization: Must use initializer functions instead of constructors
  3. Function selectors: Be careful with signature collisions
  4. Access control: Secure the upgrade functions properly
  5. Storage gaps: Include them to allow for future state variables

Each pattern has its strengths and weaknesses, and the right choice depends on your specific requirements around security, gas efficiency, complexity, and upgradeability needs.