The Chainlens Guide to Proxy Contracts on Ethereum

Andrii Kliui
Chainlens
7 min readOct 2, 2024

--

Proxy contracts are an essential tool in Ethereum and other EVM-compatible networks, enabling developers to separate a contract’s logic from its data storage. In essence, a proxy contract acts as a middleman: it delegates function calls to another contract — often referred to as the implementation or logic contract — where the actual code execution takes place. This separation is vital for achieving upgradability while preserving the contract’s state (data).

The fundamental idea behind proxy contracts is to allow for the upgrade or replacement of the implementation contract without changing the state or address of the proxy contract. This allows developers to fix bugs, add new features, or upgrade the logic without requiring users to interact with a new contract.

In this article, we’ll explore the importance of proxy contracts, their common use cases, and the different standards. We’ll also discuss how to recognize them on the blockchain.

What are Proxy Contracts?

A proxy contract is a smart contract on the Ethereum network that delegates all or most of its function calls to another contract, known as the implementation contract or logic contract. The proxy itself contains minimal logic, primarily serving as a gateway to forward requests (typically using a call that allows it to execute code from another contract in its own context) to the implementation contract, which holds the actual business logic and data processing rules.

The key idea is to separate the contract’s state (data storage) from its logic (code). The logic can then be upgraded or modified without affecting the stored data.

Why are Proxy Contracts Important?

Upgradability

Once a smart contract is deployed on Ethereum, its code is immutable and cannot be changed. This is beneficial for ensuring trust and transparency. However, it becomes a problem when developers need to fix bugs, add features, or upgrade the system.

Proxy contracts solve this by allowing the contract logic to be upgraded without affecting the data. The proxy contract always points to the current implementation contract. You can upgrade the implementation contract without losing state or requiring users to migrate to a new contract.

Gas Efficiency

Deploying large, complex contracts can be expensive due to high gas costs, especially when deploying the same contract multiple times (e.g., in a factory pattern).

By using proxies, such as ERC-1167 minimal proxy contracts (see below), you can deploy lightweight proxy contracts that delegate logic execution to a single, centralized implementation contract. This reduces gas costs because the proxy contract is much smaller and simpler.

Better Security with LowerMaintenance

Discovering a vulnerability or bug in a smart contract after deployment can result in significant losses or security issues, as the immutable nature of the blockchain makes patching difficult.

Proxy contracts enable developers to push security updates or bug fixes by pointing the proxy to a new implementation contract. This allows contract creators to maintain their contracts post-deployment without affecting users’ data or requiring them to interact with new addresses.

Unfortunately, there have been increasing cases of fraud involving proxy contracts. In these cases, attackers replace the implementation contract with one containing vulnerabilities. Thus, in some areas, the use of proxy contracts is considered a red flag.

Modularity Plus Flexibility

Proxy contracts support modular design by separating the logic into different facets, such as in the ERC-2535 Diamond Standard (see below). This allows you to replace, add, or remove modules (or facets) as needed, providing greater flexibility in building and maintaining complex decentralized applications (DApps).

Common Types of Proxy Contracts

There are several different proxy standards on Ethereum, each serving specific purposes:

ERC-1167 (Minimal Proxy / Clone Factory)

Provides a way to create minimal proxy contracts, which are highly gas-efficient and delegate all logic to a master implementation contract. This is commonly used in factory patterns where you need many instances of the same logic.

ERC-1822 (UUPS — Universal Upgradeable Proxy Standard)

In this model, the logic for upgrading is in the implementation contract itself. This provides flexibility but requires careful management of upgradeability.

ERC-1967 (Ethereum Proxy Standard)

Defines standard storage slots for proxy implementation and admin addresses, making proxy contract management easier and more transparent.

ERC-2535 (Diamond Standard)

A more advanced proxy mechanism that allows multiple “facets” (modular contracts) to be added, removed, or replaced. This is useful for complex systems where different parts of the contract need to evolve independently.

How to Recognize Proxy Contracts

Since each contract has a different implementation and its own unique interface, we need to evaluate each implementation individually to identify proxy contracts. Let’s explore the features in the contracts that will help us determine whether a contract belongs to a proxy contract.

ERC-1167 (Minimal Proxy Contract)

  • Pattern: ERC-1167 contracts use the “minimal proxy” or “clone” pattern, which involves deploying a small, fixed bytecode that delegates all calls to an implementation contract.
  • Proxy Bytecode: The proxy code will usually look like this:

0x363d3d373d3d3d363d73<implementation_address>5af43d82803e903d91602b57fd5bf3

0х3d3d3d3d363d3d37363d73<implementation_address>5af43d3d93803e602a57fd5bf3

  • 0x363d3d373d3d3d363d73 standard ERC-1167 proxy contract.
  • 0х3d3d3d3d363d3d37363d73 ERC-1167 Proxy Minimal modification.
  • <implementation_address> is the address of the contract being cloned.

ERC-1822 (Universal Upgradeable Proxy Standard — UUPS)

  • Proxy Structure: UUPS proxies usually store the address of the implementation contract in a specific storage slot (bytes32(keccak256(‘eip1967.proxy.implementation’)) — 1)
  • This storage slot have next address: c5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7
  • How to detect: Check if the contract uses this specific storage slot for the contract implementation and forwards calls to the implementation contract. Look for functions like upgradeTo.

ERC-1967 (Proxy and Beacon Standard)

  • Pattern: ERC-1967 proxies store the implementation and admin addresses in predefined storage slots:
  • Implementation contract address keccak256(‘eip1967.proxy.implementation’) — 1
    This storage slot have next address: 360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
  • Proxy admin address
    keccak256(‘eip1967.proxy.admin’) — 1
  • Upgrade Functions: ERC-1967 proxies also include upgrade functions (upgradeTo, upgradeToAndCall).
  • How to detect: You can check the storage slots at the appropriate locations to determine if the contract conforms to ERC-1967. The contract should also use DELEGATECALL to forward logic execution to the implementation contract.

ERC-2535 (Diamond Standard)

  • Pattern: ERC-2535, also known as the Diamond Standard, enables multiple facets (modular contracts) to be attached to a single proxy, with each facet handling a specific set of functions.
  • How to Detect: ERC-2535 contracts manage different “facets” that handle function calls. You can recognize them by the presence of the facetAddresses(). The storage pattern will also differ from the typical proxy implementation, as functions and addresses of facets are mapped dynamically.

Proxy Contracts in Chainlens

Chainlens simplifies identifying and analyzing proxy contracts on EVM-compatible networks. By supporting different proxy standards, Chainlens identifies and labels contracts that implement proxy patterns.

This allows developers and users to explore smart contracts and their underlying structures, even when the contracts aren’t verified. By parsing bytecode and identifying common patterns, the explorer helps uncover critical information, such as the proxy’s implementation address, storage slots, and upgrade functions.

Which Proxy Pattern is the Best

Transparent Proxy (EIP-1967):

  • Best for: Projects needing a simple, secure upgrade mechanism.
  • Why: Clear separation of roles (admin vs. users), low risk of function collisions, widely used in OpenZeppelin contracts.
  • Trade-off: Slightly higher gas cost for admin functions.

UUPS Proxy (EIP-1822):

  • Best for: Projects with high transaction volume, where gas efficiency is important.
  • Why: More gas-efficient for users, smaller proxy contract.
  • Trade-off: Upgrade logic is in the implementation, requiring careful management to avoid errors.

Beacon Proxy (EIP-2535):

  • Best for: Large-scale projects needing simultaneous upgrades for multiple contracts.
  • Why: Centralized upgrade management through a beacon, reducing complexity in large systems.
  • Trade-off: More complex and introduces additional risk with the beacon.

Summary

Each of these proxy standards — ERC-1167, ERC-1822, ERC-1967, and ERC-2535 — has a unique approach to managing implementation addresses, handling upgrades, and delegating logic. By examining the storage slots, function signatures, and bytecode, you can identify the type of proxy contract in use. This helps developers and users understand the behavior and upgradeability of the smart contracts they interact with, which is essential for maintaining secure and efficient decentralized applications.

With Chainlens’ support for proxy contracts, it’s straightforward for users to track their usage on networks. Additionally, with Chainlens’ ability to manage verified smart contracts, you can invoke update functions directly via its UI, simplifying contract management.

If you’d like to check out some proxy contracts in Chainlens, you can see some examples on Holesky here.

If you’d like to run Chainlens on your network, please contact us to learn more.

--

--