This article is written by the highly experienced security team at SafeEdges. Our team has successfully completed over 200 security audits, securing a total of $2.3 billion in assets. We have identified and mitigated numerous critical vulnerabilities before they could be exploited by attackers.

Safe Edges is a key security partner of Fuel Network, Bera, and Sei, Soon VM and is actively working across multiple Layer 1 and Layer 2 ecosystems — including those with upcoming virtual machines.

We invite you to now explore this high-level article, and we thank you for reading.

Understanding the Diamond Proxy Pattern (EIP-2535): A Comprehensive Guide

Introduction

As smart contract-based applications grow in complexity, developers often encounter the inherent size limit of a single smart contract on the Ethereum Virtual Machine (EVM), which is approximately 24KB. This limitation restricts the number of functions and features that can be implemented in a single contract. To overcome this constraint, Ethereum Improvement Proposal 2535 (EIP-2535) introduces the Diamond Standard, commonly referred to as the Diamond Proxy.

The Diamond Proxy enables the development of highly modular, extensible, and upgradeable smart contracts that can overcome code size restrictions. It achieves this by splitting the logic into multiple smaller contracts, known as facets, and routing function calls through a central proxy contract, referred to as the diamond.

This article provides an in-depth explanation of the Diamond Proxy pattern, its architecture, how it compares to other proxy standards like Transparent Proxy and UUPS Proxy, and best practices for secure implementation.

The Problem with Upgradeability

Before we jump into diamonds, let’s briefly touch on why upgradeability is tricky.

Typical proxy patterns like Transparent and UUPS proxies let you upgrade your contract by pointing a proxy to a new implementation contract. But they suffer from:

  • Limited size (still hitting that 24KB limit eventually)
  • Lack of modularity (one giant contract file)
  • Clunky management of function selectors and storage

That’s where the EIP-2535: Diamond Standard comes in.

What is a Diamond Proxy?

A Diamond Proxy is a type of upgradeable proxy pattern defined in EIP-2535. Unlike traditional proxy patterns that delegate all logic to a single implementation contract, a Diamond Proxy routes calls to many implementation contracts, known as facets. Each facet can contain a subset of the overall contract functionality.

This approach allows developers to bypass the EVM’s maximum contract size limitation and construct highly modular systems. Each function in a Diamond Proxy is associated with a function selector, which is mapped to a specific facet address responsible for executing that function via delegatecall.

Key advantages of the Diamond pattern include:

  • Support for virtually unlimited functions
  • Ability to add, remove, or replace functionalities at a granular level
  • Enhanced modularity and separation of concerns

Core Architecture

The architecture of a Diamond Proxy revolves around four main components:

1. Diamond Contract

The diamond is the main proxy contract that receives external calls and delegates them to the appropriate facet. It stores a mapping of function selectors to facet addresses.

2. Facets

Facets are individual smart contracts that encapsulate specific features or modules of the application. Each facet implements one or more functions and can be updated or replaced independently.

3. DiamondCut

The diamondCut function is used to modify the mapping between function selectors and facet addresses. It supports three operations:

  • Add: Introduce new function selectors mapped to a new or existing facet.
  • Replace: Redirect existing function selectors to new implementations.
  • Remove: Detach function selectors from their current facet addresses.

This function is critical for managing upgrades and should include appropriate access control.

4. Diamond Loupe

The diamond loupe is a special facet (or set of functions) defined in EIP-2535 that allows introspection into the structure of the diamond. It exposes the following functions:

  • facets(): Returns all facet addresses and their associated selectors.
  • facetFunctionSelectors(address facet): Returns function selectors for a given facet.
  • facetAddresses(): Returns all unique facet addresses.
  • facetAddress(bytes4 selector): Returns the facet address for a given function selector.

These functions enable external tools and users to inspect the modular layout of the diamond proxy.

Function Routing: The Role of the Fallback Function

In a Diamond Proxy, the fallback function plays a central role in routing function calls. When a function is called that is not explicitly defined in the diamond, the fallback function is triggered.

Get Safe Edges’s stories in your inbox

Join Medium for free to get updates from this writer.Subscribe

The fallback function performs the following operations:

  1. Extracts the function selector from msg.sig
  2. Looks up the facet address associated with that selector
  3. Executes the function on the facet using delegatecall

This process is similar to how traditional proxies work, with the primary difference being that the function routing in a diamond is determined dynamically based on the selector-to-facet mapping, whereas traditional proxies always delegate to a single implementation address.

Managing Facets Using diamondCut

The diamondCut function is the mechanism by which a diamond proxy is upgraded. The function takes an array of FacetCut structs, each specifying:

  • The facet address to add or remove
  • An array of function selectors to be managed
  • The action type (Add, Replace, Remove)

A sample interface of the diamondCut function looks like:

function diamondCut(
FacetCut[] calldata _facetCuts,
address _init,
bytes calldata _calldata
) external;

Where FacetCut is defined as:

struct FacetCut {
address facetAddress;
FacetCutAction action;
bytes4[] functionSelectors;
}

This function allows for highly customizable upgrades and requires strict access control mechanisms to prevent unauthorized modifications.

Storage Management Strategies

Proper storage management is crucial in proxy-based architectures, particularly in the Diamond Proxy, due to the presence of multiple logic contracts accessing shared storage.

1. Diamond Storage

This approach involves assigning each facet a unique storage slot using an identifier such as a keccak256 hash. Each facet then uses inline assembly to reference its own dedicated storage space.

This approach helps prevent storage collisions between facets.

2. AppStorage

AppStorage is a more straightforward and convenient strategy where all facets share a single AppStorage struct. The struct contains all shared state variables and is declared in storage slot zero. All facets access this shared storage layout consistently, reducing complexity.

Developers must ensure that no state variables are declared outside of the AppStorage struct and must add new variables only at the end to avoid overwriting existing data.

3. Mixed Strategy

A hybrid approach can also be used where some facets utilize shared AppStorage, and others use independent diamond storage patterns for isolation or encapsulation. Regardless of the strategy, it is essential to avoid variable collisions and maintain consistency during upgrades.

Comparison with Transparent and UUPS Proxies

Feature Diamond Proxy (EIP-2535) Transparent Proxy (EIP-1967) UUPS Proxy Number of logic contracts Multiple (facets) Single Single Upgrade granularity Function-level Full contract Full contract Upgrade mechanism diamondCut upgradeTo via Admin upgradeTo via function Contract size limit workaround Yes No No Storage complexity High Medium Medium Modularity High Low Low OpenZeppelin support No Yes Yes

Security Best Practices

The flexibility of the Diamond Proxy pattern comes with significant responsibility. Improper implementation can lead to critical vulnerabilities. Below are essential best practices:

  1. Break logic into isolated facets to promote modularity and easier testing.
  2. Protect the diamondCut function with proper access controls such as ownership or multi-signature wallets.
  3. Initialize the diamond contract with the DiamondCutFacet during deployment to enable functionality upgrades.
  4. Add new variables only at the end of storage structs to prevent data corruption.
  5. Avoid declaring variables outside of AppStorage if using the AppStorage pattern.
  6. Avoid nesting structs inside other structs unless they are immutable.
  7. Do not add new state variables to structs used in arrays, as this can lead to layout mismatches.
  8. Ensure each struct uses a unique storage slot to avoid overlapping state data.
  9. Protect the initialize() function to prevent re-initialization attacks or contract takeovers.

Real-World Usage

Several real-world protocols and development teams have adopted the Diamond Proxy pattern for complex and modular applications. Examples include:

  • Aavegotchi Protocol
  • Mugen Finance
  • Various DAOs and NFT projects seeking upgradeable and extensible architecture

Conclusion

The Diamond Proxy (EIP-2535) offers a powerful solution to the limitations of traditional smart contract architectures, especially for large-scale decentralized applications. By modularizing logic across multiple facets and enabling granular upgrades, the diamond pattern allows developers to build sophisticated and maintainable systems.

However, the pattern introduces complexity in storage management, access control, and upgrade safety. Developers must carefully follow security best practices and thoroughly test each component.

While tools and frameworks for Transparent and UUPS proxies are well-established, the Diamond Proxy pattern is still maturing and often requires custom implementations. As the ecosystem grows and more best practices are formalized, the Diamond Proxy will likely become a critical tool in the toolkit of advanced Ethereum developers.

References

Thank you for reading. We hope you learned something new today. Don’t forget to subscribe to our newsletter, and of course, check out our latest articles we regularly add in-depth insights and updates.

LEAVE A REPLY

Please enter your comment!
Please enter your name here