How to use Ownable with upgradeable contract?

I get this error when compiling a project that imports Ownable:
Use @openzeppelin/contracts-ethereum-package instead.

Either one of these two tutorials is outdated. Which one is the up-to-date one? Can you please update the outdated tutorial?

https://docs.openzeppelin.com/learn/deploying-and-interacting
$ npm install --save-dev @openzeppelin/cli

https://docs.openzeppelin.com/cli/2.6/dependencies#linking-the-contracts-ethereum-package
$ npx oz link @openzeppelin/contracts-ethereum-package

Cheers,
David

2 Likes

Hi @dportabella,

Welcome to the community :wave:

What kind of contract do you want to create? Do you want to create a regular or an upgradeable contract?

The guide on https://docs.openzeppelin.com/learn/deploying-and-interacting is for regular contracts.

The guide on https://docs.openzeppelin.com/cli/2.6/dependencies#linking-the-contracts-ethereum-package is for upgradeable contracts.

Regards OpenZeppelin Contracts Ethereum Package:

This package contains the same contracts as the vanilla OpenZeppelin Contracts, but modified for use with upgradeable contracts. The main difference is that all contracts in this package are potentially upgradeable : you will notice that no contracts have constructors defined, but use initializer functions instead. Also, this package is set up as an Ethereum package, and provides a small set of pre-deployed logic contracts that can be used directly via the OpenZeppelin SDK, without needing to deploy them again.

Thanks for the reply.
Wouldn’t it be possible to make a library to is compatible both for regular and for upgradable contracts?
I want to create an upgradable contract, importing the Ownable contract.
If I import @openzeppelin/contracts/access/Ownable.sol, it complains that Ownable uses a constructor.
How I import the Ownable contract in a upgradable contract?

Cheers, David

1 Like

Hi @dportabella,

To use Ownable in an upgradeable contract we need to do the following:

Import OwnableUpgradeSafe as contracts in OpenZeppelin Contracts Ethereum Package have an UpgradeSafe suffix to avoid confusion with their counterparts in OpenZeppelin Contracts.

Create an initialize function to initialize the contract and use the initializer modifier from Initializable to ensure that it is only called once.

An upgradeable version of Box.sol (from: https://docs.openzeppelin.com/learn/developing-smart-contracts#importing_openzeppelin_contracts) using Ownable is shown below:

Box.sol

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

// Import Ownable from the OpenZeppelin Contracts library
import "@openzeppelin/contracts-ethereum-package/contracts/access/Ownable.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/Initializable.sol";

// Make Box inherit from the Ownable contract
contract Box is Initializable, OwnableUpgradeSafe {
    uint256 private value;

    event ValueChanged(uint256 newValue);

    function initialize() public initializer {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }

    // The onlyOwner modifier restricts who can call the store function
    function store(uint256 newValue) public onlyOwner {
        value = newValue;
        emit ValueChanged(newValue);
    }

    function retrieve() public view returns (uint256) {
        return value;
    }
}

I recommend looking at Role-Based Access Control for more finely controlled access control.


I assume you mean a version of OpenZeppelin Contracts that could be used with regular contracts and upgradeable contracts.

A single version would require contracts to have both constructors and initializers, increasing the complexity, along with the gas costs of deployment.

Please ask all the questions that you need.

Ok, thanks.

If we cannot have a unique library for both regular and upgradable contracts,
then we need the API docs for both.

API docs for regular contracts:
https://docs.openzeppelin.com/contracts/3.x/

Where is the API doc for upgradable contracts?

Thanks again!
David

1 Like

Hi @dportabella,

The same API documentation for OpenZeppelin Contracts can be used with OpenZeppelin Contracts Ethereum Package. The differences are an UpgradeSafe suffix on the contract and using initializers rather than constructors.

from OpenZeppelin Contracts Ethereum Package: https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package#differences-with-openzeppelin-contracts

This package contains the same contracts as the vanilla OpenZeppelin Contracts, but modified for use with upgradeable contracts. The main difference is that all contracts in this package are potentially upgradeable : you will notice that no contracts have constructors defined, but use initializer functions instead. Also, this package is set up as an Ethereum package, and provides a small set of pre-deployed logic contracts that can be used directly via the OpenZeppelin SDK, without needing to deploy them again.

All contracts have an UpgradeSafe suffix to avoid confusion with their counterparts in OpenZeppelin Contracts. For example, ERC20 becomes ERC20UpgradeSafe .

All in all, you should use this package instead of @openzeppelin/contracts if you are creating upgradeable contracts .

Thanks a lot for the Box.sol example above!

this shows what’s required to move to upgradeable contracts with the OpenZeppelin themself:

  1. change imports (point to @openzeppelin/contracts-ethereum-package) for all contract imports
  2. derive Box from both Initializable and ownableUpgradeSafe (in that order) - I guess this is to make both Box and Ownable upgradeable
  3. call base class initialize implementation functions - for which I have to look at the source (implementation) of the respective OpenZeppelin contract inherited (OwnableUpgradeSafe in this case)

FWIW, I spent quite some time with the docs: I could find 1. there, but the infos 2. and 3. I didn’t find (only here in your answer).

With 3.: as a app developer using OZ contracts, am I supposed to read the implementation to figure out the right functions to call in the base class (inside initialize). Eg in my case, with AccessControlUpgradeSafe, I am supposed to call __Context_init_unchained and __AccessControl_init_unchained … I guess)

IOW: please add this information to the docs.

1 Like

Hi @oberstet,

Thanks for the feedback on the your experience with OpenZeppelin Contracts Ethereum Package. I am sorry that all the information you needed wasn’t in the one place.

We have some brief documentation but not as explicit as they could be to cover your three points.
https://docs.openzeppelin.com/upgrades/2.8/writing-upgradeable#use-upgradeable-packages

I created an issue: https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/issues/99

I added this feedback to: The Future of contracts-ethereum-package

Thanks a lot for taking note, and for improving docs! -/

fwiw, I now have the basics working. I am now fighting ripples affecting our EIP712/state-channel code …

1 Like

I had this exact same problem. I had previously been using the regular contracts library, but now see I should use the ‘contracts-ethereum-package’. One easy step is I think it would be helpful for this to be made clearer in the upgrades section of the docs, or in the contracts library README. Even after reading a lot of the OZ docs, I didn’t realize this until I started actually trying to deploy upgradeable contracts, and realizing that Ownable wouldn’t work. I do realize it technically on this page, but it’s a bit buried and I totally missed it.

Anyway, thanks for everything! Very helpful libraries, and I love what OZ is doing.

1 Like

Hi @blakewest,

Thanks for the feedback. It is really appreciated. :pray:

I have created the following issues:


Feel free to add to the issues any more detail on what would be useful in the documentation for the community.

Check out the new guide!

1 Like