Initial value in upgrade contract

Hi, I am trying to use upgrades-plugins, and follow this doc, and now I have some questions about it:
avoid-initial-values-in-field-declarations, so according to the doc, I can not use

uint256 public constant hasInitialValue = 42;

I have to use as shown below:

function initialize() public initializer {
        hasInitialValue = 42;
    }

So why can not I use the first way, I think if I have set the variable visibility as constant, it is ok in the proxy pattern.

1 Like

Hi @Skyge,

Initial values in field declarations are similar to constructors. You would be setting the state in the implementation contract when we need to set state in the proxy.

Instead we can use constants.

From: https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#avoid-initial-values-in-field-declarations

Note that it is still fine to define constant state variables in this way, because the compiler does not reserve a storage slot for these variables, and every occurrence is replaced by the respective constant expression. So the following still works with OpenZeppelin Upgrades:

contract MyContract {
   uint256 public constant hasInitialValue = 42;
}

Emmmm ,so is this a special requirement in the upgrades-plugins or should this be done in every proxy contract, I mean if I do not use upgrades-plugins, just use the original proxy contract to deploy.

BTW, could you please tell me, why I can not use constant in the proxy pattern, I always think for a constant variable, it is deployed in the implementation contract and we read from it, please correct me if I have misunderstood anything!

1 Like

Hi @Skyge,

Not using constructors and initial values in field declarations is a requirement for proxy contracts and isn’t specific to the Upgrades Plugins.

The same is required with minimal proxies as an example.

If you are deploying from scripts then I recommend using Upgrades Plugins for deployment and test, as they make this task easier and check for upgrade safety.

If you are deploying from Solidity then you could use the proxy contracts in OpenZeppelin Contracts: https://docs.openzeppelin.com/contracts/3.x/api/proxy
You could still use the Upgrades Plugins to do some higher level tests for upgrade safety.

We can use constants in our implementation contracts. Apologies if the documentation or my explanation isn’t clear.

Can you think of a better way that I can explain this which would help the community?

Okay, I think the doc gives a bad example, yeah, I know, in order to use proxy pattern, I should set all initial values in an initializer function, so I think we can write like this:

Solidity allows defining initial values for fields when declaring them in a contract.

contract MyContract {
    uint256 public hasInitialValue = 42;     <<<<------- remove constant at here 
}

This is equivalent to setting these values in the constructor, and as such, will not work for upgradeable contracts. Make sure that all initial values are set in an initializer function as shown below; otherwise, any upgradeable instances will not have these fields set.

contract MyContract is Initializable {
    uint256 public hasInitialValue;

    function initialize() public initializer {
        hasInitialValue = 42;
    }
}

So now we can say Note that it is still fine to define constant state variables in this way,

contract MyContract {
    uint256 public constant hasInitialValue = 42;
}

At least for me, this is more clear.

1 Like

Hi @Skyge,

Great feedback :pray:

I have created a PR to improve the documentation: https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/236

Thanks for your contributions!!