The Diamond pattern helps build big smart contracts by splitting them into smaller parts. It keeps code organized and easy to update.
Diamond pattern (EIP-2535) in 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.
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()) }
}
}
}contract FacetA {
function greet() external pure returns (string memory) {
return "Hello from Facet A!";
}
}// Adding a facet to the diamond
facets[bytes4(keccak256("greet()"))] = address(facetA);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.
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()) } } } }
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.
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.