How to upgrade a contract deployed with version 4.9.0 using 5.0.0 contracts?

I have an upgradable contract that uses OpenZeppelin version 4.9.0. This contract is deployed on Ethereum. OpenZeppelin version 5.0.0 has been released. My questions: Next time I upgrade the smart contract

  1. Could I use new v5 contracts ?
  2. Could I replace the v4 contracts with v5 contracts ?
  3. Will the OpenZeppelin upgrade plugin identify errors/conflicts if they exists?

The following code to reproduce is only an example (would probably not cause a problem because it is simple). But my question is more general about upgrades between different breaking changes versions of OpenZeppelin and the recommendation of the developers ?

Thank you

:1234: Code to reproduce

The code of the deployed upgradable contract

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/token/ERC20/IERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/token/ERC20/utils/SafeERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.9.0/contracts/proxy/utils/Initializable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.9.0/contracts/proxy/utils/UUPSUpgradeable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.9.0/contracts/access/AccessControlUpgradeable.sol";

contract ExampleV1 is Initializable, UUPSUpgradeable, AccessControlUpgradeable {
  using SafeERC20 for IERC20;

  uint256 counter;

  constructor() {
      _disableInitializers();
  }

  function initialize(
    address admin
  ) public initializer {
    __UUPSUpgradeable_init();
    __AccessControl_init();
    _grantRole(DEFAULT_ADMIN_ROLE, admin);
  }

  function _authorizeUpgrade(
    address newContractAddress
  ) internal view override onlyRole(DEFAULT_ADMIN_ROLE) { }

  function doSomething() external {
    counter++;
  } 

  function getVersion() public pure returns (string memory) {
    return "Example Version 1";
  }
}

The new implementation contract that I would deploy and then set the proxy to:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/token/ERC20/IERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/token/ERC20/utils/SafeERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v5.0.0/contracts/proxy/utils/Initializable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v5.0.0/contracts/proxy/utils/UUPSUpgradeable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v5.0.0/contracts/access/AccessControlUpgradeable.sol";

contract ExampleV2 is UUPSUpgradeable, AccessControlUpgradeable {
  using SafeERC20 for IERC20;

  uint256 public counter;

  function _authorizeUpgrade(
    address newContractAddress
  ) internal view override onlyRole(DEFAULT_ADMIN_ROLE) { }

  function doSomething() external {
    counter = counter + 2;
  } 

  function getVersion() public pure returns (string memory) {
    return "Example Version 2";
  }
}

:computer: Environment

Hardhat / Remix

  • Could I use new v5 contracts ?

It is not safe to upgrade an existing deployment from 4.x to 5.x. See Contract upgrade failed because variables are deleted in openzepplin 5.0 - #2 by ericglau

  • Could I replace the v4 contracts with v5 contracts ?

If you do replace them (note there are some differences in usage), the new contract can only be used for new proxy deployments. As above, you cannot upgrade an existing deployment to a different major version of OpenZeppelin Contracts.

  • Will the OpenZeppelin upgrade plugin identify errors/conflicts if they exists?

Conflicts will definitely exist across major version changes. The upgrades plugin will identify them, but you should not even attempt this kind of upgrade because it is known to be unsafe.

1 Like

@ericglau I wrote a small article about it https://medium.com/51nodes/why-upgrading-openzeppelin-smart-contracts-from-version-4-to-version-5-is-unsafe-e08be30efd8a

thanks for your help

1 Like

This is nonsense.
This could cause a big problem.
It could've been prevented from contract level

OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility. As per semantic versioning, major versions can have changes that are incompatible with previous versions. Such changes can be used to make improvements that are important enhancements but not backwards compatible.

This is described in the readme and you can read more about it in the documentation at https://docs.openzeppelin.com/contracts/5.x/backwards-compatibility.

1 Like

I understand the complexities involved, but we are dealing with smart contracts that could potentially lead to substantial financial losses. It would have been prudent to implement a version check before allowing any upgrades.

Is there a way to roll back this situation? The initialize function is also not functioning as expected.

you don't think this might cause a problem?

The documentation and repository linked above clearly states that upgrades between major versions are NOT supported.

Documentation suggests using Upgrades Plugins to perform upgrades, which validates storage layout compatibility and helps to prevent this kind of incompatible upgrade. It is also best practice to test upgrades before upgrading contracts in production.

A post was merged into an existing topic: [Emergency] UUPS Proxy contract not working after using zeppelin upgradeable v5.0.0