Constructor Functions Don't Work in Facets
Use a diamond proxy constructor function or the `diamondCut` function.
Constructor functions are used to set state variables in the contract storage of a contract that is being deploy.
But realize that a facet (used by a diamond) doesn’t read or write to anything in its own contract storage — it only reads and writes state variables to a diamond proxy’s contract storage. A diamond proxy contract is a single source for all state variable data. Facets provide the code and state variable definitions that are used to read and write to a dimond proxy’s contract storage.
Another way to say this is that any data stored in a facet’s contract storage is ignored by a diamond. A facet’s constructor function stores data in the facet’s contract storage, so that gets ignored by a diamond.
There are two places state variable data can be stored -- in a diamond proxy contract, or in a facet. A diamond (which is a diamond proxy contract and facets) only read/write the data in the diamond proxy contract. The diamond proxy contract is the contract with the fallback function that is used to delegate function calls to facets.
How to Initialize State When Deploying or Upgrading a Diamond
When deploying a diamond put any initialization code, including setting state variables, in the constuctor function of the diamond proxy contract.
When upgrading a diamond using diamondCut
use the second and third arguments of diamondCut
to execute a function with delegatecall to run any initialization code and set state variables. Check the EIP2535 Diamonds standard to understand how the diamondCut function works.
Understand that constants can be set in facets. And immutable variables can be set in constructor functions of facets, because these are stored as part of a contract’s bytecode, and are not stored in contract storage.