How to initialize new version when upgrading?

Hi, following the question and given example

ragma solidity >=0.4.22 <0.9.0;

contract BoxV1 {
    uint256 private a;
    uint256 private b;

    function initialize() public initializer {
        // Something meaningful here
    }

    function store(uint256 _a, uint256 _b) public {
        a = _a;
        b = _b;
    }

    function add() public view returns (uint256) {
        return a + b;
    }

}

contract BoxV2 {
    uint256 private a;
    uint256 private b;
    uint256 private c;

    function initializeV2(uint256 _c) public initializerV2(?) {
        c = _c;
    }

    function store(uint256 _a, uint256 _b) public {
        a = _a;
        b = _b;
    }

    function add() public view returns (uint256) {
        return a + b + c;
    }

}

As state is stored in the proxy, if when you upgrade, you need to initialize state in an upgrade function, then you would need to call the upgrade function for each proxy.

Please note you should protect the upgrade function so that it can only be called once, and if it isn’t called in the same transaction as the upgrade, then it also needs to be protected so that only you can call it.

There is an upgradeToAndCall function in the AdminUpgradeabilityProxy, used in upgrades plugins. I assume correct way to upgrade to BoxV2 in the example above is (please correct me if I’m wrong):

  1. Deploy V2
  2. Call upgradeToAndCall on the proxy, pass address from v2 and packed initialize with argument c in data (question: do I need to also make initializerV2 modifier? Because in general, _initialized already set to true in the proxy storage)

Unfortunately, I struggle to find examples of the usage. It seems upgrade and call is not supported by hardhat plugin. In basic example upgrade proxy method was used, which doesn’t have any arguments to pass additional data. Do I need to manually call this method?

1 Like

Hi @ifro,

To initialize state when upgrading we can create an initializeV2 function as you have done. We need to ensure that this function can only be called once, and it can only be called by us (or be coded so it is safe for anyone to call it).

There is an open issue to call the function as part of the upgrade:

For now we need to call initializeV2 in a separate transaction after the upgrade.

We can protect this function by checking for an uninitialized value, or by using a boolean.
To ensure that it is only called by us, you may need some access control to check for the contract deployer.

Thanks. As far as I can understand there is a way to use a cli for upgrading in the same transaction, am I right?
https://docs.openzeppelin.com/cli/2.8/commands#upgrade

1 Like

Hi @ifro,

The OpenZeppelin CLI supported calling a function as part of an upgrade.

Please note: We’ve decided it’s best to focus our upgradeability efforts on the Upgrades Plugins exclusively, and have halted development on the OpenZeppelin CLI. See: Building for interoperability: why we’re focusing on Upgrades Plugins

The OpenZeppelin Upgrades Plugins don’t have this functionality currently, hence we need to call the function in a separate transaction, ensuring it is only called once and is protected so only we can call it.

1 Like