0
0
Blockchain / Solidityprogramming~10 mins

Diamond pattern (EIP-2535) in Blockchain / Solidity

Choose your learning style9 modes available
Introduction

The Diamond pattern helps build big smart contracts by splitting them into smaller parts. It keeps code organized and easy to update.

When your smart contract is too large and complex to manage as one piece.
When you want to add new features to a contract without redeploying everything.
When you want to fix bugs or improve parts of a contract without affecting others.
When you want to share code between multiple contracts safely.
When you want to save gas by reusing code modules.
Syntax
Blockchain / Solidity
contract Diamond {
    // Holds addresses of facets (modules)
    mapping(bytes4 => address) public facets;

    // Fallback function to delegate calls to facets
    fallback() external payable {
        address facet = facets[msg.sig];
        require(facet != address(0), "Function does not exist");
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }
}

The Diamond contract holds references to smaller contracts called facets.

Calls to functions are forwarded to the right facet using delegatecall.

Examples
This is the core Diamond contract that forwards calls to facets.
Blockchain / Solidity
contract Diamond {
    mapping(bytes4 => address) public facets;

    fallback() external payable {
        address facet = facets[msg.sig];
        require(facet != address(0), "Function does not exist");
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }
}
A simple facet contract with one function.
Blockchain / Solidity
contract FacetA {
    function greet() external pure returns (string memory) {
        return "Hello from Facet A!";
    }
}
Maps the function selector of greet() to the FacetA address.
Blockchain / Solidity
// Adding a facet to the diamond
facets[bytes4(keccak256("greet()"))] = address(facetA);
Sample Program

This program shows a Diamond contract that forwards the greet() call to FacetA. When you call greet() on Diamond, it returns the greeting from FacetA.

Blockchain / Solidity
pragma solidity ^0.8.0;

contract FacetA {
    function greet() external pure returns (string memory) {
        return "Hello from Facet A!";
    }
}

contract Diamond {
    mapping(bytes4 => address) public facets;

    constructor(address _facetA) {
        facets[bytes4(keccak256("greet()"))] = _facetA;
    }

    fallback() external payable {
        address facet = facets[msg.sig];
        require(facet != address(0), "Function does not exist");
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }
}
OutputSuccess
Important Notes

Diamond pattern uses delegatecall to run code in the context of the main contract.

Function selectors (first 4 bytes of function signature hash) are used to route calls.

Updating facets lets you add or fix features without redeploying the whole contract.

Summary

The Diamond pattern splits big contracts into smaller parts called facets.

It forwards function calls to the right facet using delegatecall and function selectors.

This makes contracts easier to manage, update, and save gas.