Why are libraries not sufficient?
It depends on the circumstances. EIP-2535 Diamonds is used for multiple things: code organization, modularity, fine grained upgrades, reusable on-chain code, smart contract protocol extension, stable address without a limit of the number of external functions. It does not replace Solidity libraries.
Correct me if I am wrong but I believe that libraries can do the following:
- code organization, yes libraries allow this
- modularity, yes
- fine grained upgrades, libraries and/ or contract can be upgraded with OZ but maybe not to the degree of Diamond
- reusable on-chain code, the main reason libraries exist
But not these:
- smart contract protocol extension,
- stable address without a limit of the number of external functions.
Edit: but I am looking for explaination that libraries can or cannot alleviate 24kb contract size limit. Please show me the where in docs this is shown
Yes, Solidity libraries can be used to help with these things.
EIP-2535 Diamonds is a general smart contract architecture for designing extensible smart contract systems. Solidity libraries are a programming language feature, not a contract architecture, though architectures could be designed that use them.
Solidity libraries are a tool for creating reusable deployed on-chain code. EIP-2535 Diamonds answers questions like this: How do I design an upgradeable smart contract system that can be easily extended in production without limit? It so happens that EIP-2535 Diamonds natively supports and solves some of the same problems that Solidity libraries do.
Solidity libraries work very nicely with diamonds, specifically using internal functions of Solidity libraries to share functions between facets. External functions from Solidity libraries can be used with diamonds too.
Edit: but I am looking for explaination that libraries can or cannot alleviate 24kb contract size limit.
Solidity libraries can be used to alleviate the 24kb contract size limit but its ability to do so is limited. External functions defined in a contract generate bytecode. So if enough external functions are added to a contract then it will hit the 24kb contract size limit. A diamond can have practically an unlimited number of external functions. This enables deployed contract system to be extended without risk of hitting a technical limit in the future.
Using Solidity libraries to reduce bytecode size means reorganizing code to get around a technical limitation rather than reorganizing code to make it better or more organized. A developer may not want to organize her code based on a bytecode size limitation. On the other hand perhaps contract architectures can be designed that use Solidity libraries in a way that is nice and not likely to hit the bytecode size limit. EIP-2535 Diamonds is a solution like that: it uses delegatecall like Solidity libraries do.
Hi!
I am looking into a smart contract structure that can be the foundation piece of a NFT based game, where one single NFT will have various attributes(character level, data, history etc.) and functions (level up, adjusting attributes, etc.). Is the EIP-2535 Diamond standard a good foundation piece for such usage?
LH
My team worked on the smart contracts and on-chain operations for Crypto Unicorns (https://cryptounicorns.fun), which uses EIP2535 proxies extensively. @Nick_Mudge works on the smart contracts for Aavegotchi, I believe. They also use the diamond standard extensively.
Diamond proxies are a great choice for games, especially, because game mechanics change over time and the diamond standard supports data/rules initialization and migrations directly in the standard.
The most important thing if you go with EIP2535 is to build good tooling around attaching/detaching facets to your core diamond contract, and introspecting on which contracts are serving which functionality.
I think you could make a lot of this work with libraries, but the diamond standard comes with a lot of batteries included. Specifically, some diamond features I have used heavily in production:
- Convenient initialization and migration of data in storage
- The ability to attach and detach individual facet methods without having to implement and manage a separate method-level lock mechanism.
Yes. For example Aavegotchi has done this.
EIP-2535 Diamonds recently became a "Final" Ethereum smart contract standard.
What are functions between Facets called? If I want to use the owner function of OwnershipFacet
to limit access to a function.
I have been testing but it does not work. It returns me an empty address.
I share code from my last test:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./OwnershipFacet.sol";
library LibA {
struct DiamondStorage {
address owner;
bytes32 dataA;
string testSring;
}
function diamondStorage() internal pure returns(DiamondStorage storage ds) {
bytes32 storagePosition = keccak256("diamond.storage.LibA");
assembly {
ds.slot := storagePosition
}
}
}
contract FacetA {
function setDataA(bytes32 _dataA) external {
LibA.DiamondStorage storage ds = LibA.diamondStorage();
ds.dataA = _dataA;
}
function getDataA() external view returns (bytes32) {
return LibA.diamondStorage().dataA;
}
function setStringData(string memory _string) external {
LibA.DiamondStorage storage ds = LibA.diamondStorage();
ds.testSring = _string;
}
function getStringData() external view returns (string memory) {
if(msg. sender != getOwner()) revert("You are not the Owner");
return LibA.diamondStorage().testSring;
}
// testing using a function from other Facet
function getOwner() public view returns (address) {
return OwnershipFacet(0x7D005138A26110bAd9075807Bb16B5527951074e).owner();
}
}
The function is public to check what value it returns when it is deployed
The current approach of using function selectors alone (i.e., the first 4 bytes of the function's signature) limits the flexibility of the Diamond standard, as it treats functions with the same name but different parameters as identical. If the Diamond pattern were extended to include both the function selectors and their parameter types, it would allow for greater versatility by enabling the same function name to be used with different parameter sets, thus supporting function overloading directly within the proxy setup.