Smart Contract Upgradeability - Diamond Proxy Pattern
Like other proxy patterns, in the diamond pattern, there is one contract called diamond that acts like a proxy contract and processes all calls from users by delegatcall to the logic contract.
But there is some big difference between diamond and other proxy patterns. You can implement multiple logic contracts in a diamond proxy pattern and break contract size limitations. The maximum size of the smart contract is 24 kB. So, if we need to organize and create a big project, we have a problem. But in the diamond pattern, we solved this problem by splitting our project into many contracts and connecting them without limiting the number of connected contracts. in a diamond pattern, we call the main contract – a diamond and logic contract – facet.
All facets are separate, independent contracts and deployed libraries. They are stateless and with no storage contract. All states in the diamond pattern can get managed in a diamond storage contract.
Like other proxy patterns, in the diamond contract, there is a fallback function that gets calls and processes them by delegatcall.
Functions and facets address are important data that we keep in the diamond contract, we can add or remove or replace them. But the first question is how we add functions and facets to the diamond contract.
First, see how we keep facets addressed and functions in the diamond contract.
As you can see in the above image, the proxy contract in the diamond pattern contains mapping. a mapping of function selectors to facet addresses. We can add/replace/remove functions from the proxy contract by modifying this mapping.
The main tools for modifying mapping from proxy are IDiamond Interface and IDiamondCut interface.
IDiamond includes FaceCutAction, as you know, we can add or remove or replace functions and facets in the diamond contract. By using this Enum we can define what we want to do.
Another data is the FaceCut struct, which contains facet or logic address and action and array of function selectors.
Another data is the DiamondCut event. Anytime we add or remove or replace any external function in the diamond contract, we need to emit a DiamondCut event. This applies to all upgrades, and all functions changes, at any time.
领英推荐
this is Transparency in diamond proxy pattern.
As you can see IDiamondCut is inherited from IDiamond and uses all data from the IDiamond. The main function of this contract is diamondCut with the three arguments.
Fcecut[] is the array of FaceCut struct, containing function selectors and facets address. If we need to initialize any data in any contract, we can use _init address and _calldata data.
By using this function, we can modify mapping in the diamond contract.
Another tool in the diamond proxy pattern is the IDiamondLoupe interface.
We use IDiamondLoupe to keep track of functions and facets address in our project. The loupe functions can be used in user-interface software. A user interface calls these functions to provide information about and visualize diamonds.
According to the above structure in the diamond proxy pattern, we use a single address for unlimited contract functionality. diamonds have no max contract size, so there is no limit to the amount of functionality that can be added to diamonds over time. The single address makes deployment, testing, and integration with other smart contracts much easier.
In the diamond proxy pattern, contracts are separated and isolated but are connected together and share functions together in a gas-efficient way. If there is deployed smart contract or library that is useful for your contract, you can use it in the diamond contract.
And anytime you can make diamond immutable.
In the diamond proxy pattern, we cannot store two same four-byte hashs. so it's not possible Function Selector Clash get happen in this pattern. this scenario is not possible with a properly implemented diamondCut function because it prevents adding function selectors that already exist.
I hope you find this post useful.