Compliance and Transparency of Immutable Functions in Diamonds
Understand these terms:
Diamond: A diamond proxy contract is the contract with the fallback function that delegatecalls to facets. It is the diamond.
Immutable Function: An immutable function is an external function defined directly in a diamond proxy contract, or is inherited by a diamond proxy contract.
The EIP-2535 Diamond standard states the following concerning immutable functions:
All immutable functions must be emitted in the DiamondCut event as new functions added. And the loupe functions must return information about immutable functions if they exist. The facet address for an immutable function is the diamond’s address. Any attempt to delete or replace an immutable function must revert.
The reason for this is transparency and showing correct data about diamonds.
Transparency
If immutable functions were not emitted in the DiamondCut event and returned by the loupe functions then people and/or tooling can be confused because DiamondCut and the loupe functions would be missing data. They would not show all the external functions in a diamond.
Worse is that the DiamondCut and loupe functions can show incorrect information about immutable functions if they are not emitted in DiamondCut and returned by the loupe functions. Look at this senario:
Immutable functions are defined directly in a diamond proxy contract and not emitted in DiamondCut and returned by the loupe functions. Let’s say that the function signature for one of the immutable functions is “addNFT(uint256)”.
The diamond is deployed.
A person with access to the diamond adds a new function to the diamond by calling the diamondCut function. The new function has the function signature “addNFT(uint256)”. This executes successfully because the diamond does not know that an immutable function already exists with that function signature — because the immutable function was never added to the loupe functions so the diamond has no way to know or check that this function already exists in the diamond.
Now when the “addNFT(uint256)” function is called on the diamond the immutable function version of it is executed because the fallback function is not called.
When people look at the DiamondCut event or the loupe function functions for the “addNFT"(uint256)” function they will be given the facet address for the function that is never used by the diamond — since the immutable function version is always used.
The above senario is why the EIP-2535 Diamonds standard requires that all immutable functions be emitted in the DiamondCut event and returned by the loupe functions. This senario never happens with a compliant EIP-2535 Diamond.