Upgradeable contract: The deployer is the owner: AssertionError

I’m running into an issue where the ‘deployer is the owner’ test fails when using the: @openzeppelin/contracts-ethereum-package

:computer: Environment
@openzeppelin/contracts-ethereum-package@2.4.0
(also tested with @openzeppelin/contracts-ethereum-package@2.2.3 after reading this thread.)

@openzeppelin/cli@2.7.1
@openzeppelin/test-environment@0.1.2
mocha@7.0.1
chai@4.2.0

I ran this to link:
npx oz link @openzeppelin/contracts-ethereum-package

:memo:Details
If i’m understanding the failure correctly it seems like a false positive as when I deploy the contract it initializes with the deployer address as the owner as expected.

Test command:
oz compile && mocha --exit --recursive test

In an attempt to identify the root of the issue I simplified down to a basic contract that I found posted in the forums. I created two separate projects, one that uses contracts-ethereum-package and one that uses @openzeppelin/contracts@2.5.0. The contract using the latter package passes the test without issue. The former fails.

:1234: Code to reproduce

// MyContract.sol - Fails test
pragma solidity ^0.5.0;

import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol"; 


contract MyContract is Ownable {
    function normalThing() public {
        // anyone can call this normalThing()
    }

    function specialThing() public onlyOwner {
        // only the owner can call specialThing()!
    }
}
//MyContract.sol - Passes test
pragma solidity ^0.5.0;

import "@openzeppelin/contracts/ownership/Ownable.sol";

contract MyContract is Ownable {
    function normalThing() public {
        // anyone can call this normalThing()
    }

    function specialThing() public onlyOwner {
        // only the owner can call specialThing()!
    }
}

Using the same test script for both:

// test/MyContract.test.js -

const { accounts, contract } = require("@openzeppelin/test-environment");

const { expect } = require("chai");

const MyContract = contract.fromArtifact("MyContract");

describe("MyContract", function() {
  const [owner] = accounts;

  beforeEach(async function() {
    this.myContract = await MyContract.new({ from: owner });
  });

  it("the deployer is the owner", async function() {
    expect(await this.myContract.owner()).to.equal(owner);
  });
});

Any insights or assistance would be most appreciated. I’m new ish to Solidity so it seems likely that i’m missing something basic.

Thanks!

1 Like

Hi @DeFiGlobal,

Welcome to the community :wave:

Upgradeable contracts don’t have constructors. So we need to initialize Ownable to set the owner. See the documentation on Initialization: https://docs.openzeppelin.com/learn/upgrading-smart-contracts#initialization

I updated MyContract and the test to show how this works, as well as testing manually using the CLI.

MyContract.sol

pragma solidity ^0.5.0;

import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol"; 
import "@openzeppelin/upgrades/contracts/Initializable.sol";

contract MyContract is Initializable, Ownable {

    function initialize(address owner) public initializer {
        Ownable.initialize(owner);
    }

    function normalThing() public {
        // anyone can call this normalThing()
    }

    function specialThing() public onlyOwner {
        // only the owner can call specialThing()!
    }
}

MyContract.test.js

Added a call to initialize in the beforeEach to set the owner.

// test/MyContract.test.js -

const { accounts, contract } = require("@openzeppelin/test-environment");

const { expect } = require("chai");

const MyContract = contract.fromArtifact("MyContract");

describe("MyContract", function() {
  const [owner] = accounts;

  beforeEach(async function() {
    this.myContract = await MyContract.new({ from: owner });
    await this.myContract.initialize(owner);
  });

  it("the deployer is the owner", async function() {
    expect(await this.myContract.owner()).to.equal(owner);
  });
});

I find it useful to manually test using the CLI
With ganache-cli running in a separate terminal ganache-cli -d

Get the accounts

$ npx oz accounts
? Pick a network development
Accounts for dev-1581565685520:
Default: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
All:
- 0: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
- 1: 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
- 2: 0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b

Create the contract and initialize the owner

$ npx oz create
Nothing to compile, all contracts are up to date.
? Pick a contract to instantiate MyContract
? Pick a network development
✓ Deploying @openzeppelin/contracts-ethereum-package dependency to network dev-1581565685520
✓ Contract MyContract deployed
All implementations have been deployed
? Call a function to initialize the instance after creating it? Yes
? Select which function * initialize(owner: address)
? owner: address: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
✓ Setting everything up to create contract instances
✓ Instance created at 0xA57B8a5584442B467b4689F1144D269d096A3daF
0xA57B8a5584442B467b4689F1144D269d096A3daF

Send a transaction from a non-owner to specialThing and it reverts.

$ npx oz send-tx --from 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
? Pick a network development
? Pick an instance MyContract at 0xA57B8a5584442B467b4689F1144D269d096A3daF
? Select which function specialThing()
✖ Calling: 'specialThing' with no arguments
Error while trying to send transaction to 0xA57B8a5584442B467b4689F1144D269d096A3daF. 
Error: Returned error: VM Exception while processing transaction: revert Ownable: caller is not the owner

Send a transaction from the owner to specialThing and it doesn’t revert.

$ npx oz send-tx
? Pick a network development
? Pick an instance MyContract at 0xA57B8a5584442B467b4689F1144D269d096A3daF
? Select which function specialThing()
✓ Transaction successful. Transaction hash: 0xd59336d06b5a895ccf053bc4d2794cc071f5192b1b51a0f9d8464268d47e7eb8
1 Like

Thanks @abcoathup that did the trick!

1 Like

Hi @DeFiGlobal,

The CLI now supports deploying regular (non-upgradeable) contracts in the release candidate of OpenZeppelin CLI 2.8

Would appreciate if you could give the release candidate a try and let us know what you think!

Oh cool. I will give it a try. Sounds nice :sunny:

1 Like

This code doesn't appear to be up to date. I don't think Ownable is even a contract when it's from the contracts-ethereum-package. I had to do this instead:

import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol"; 
import "@openzeppelin/contracts-ethereum-package/contracts/Initializable.sol";

contract MyContract is Initializable, OwnableUpgradeSafe {
  function initialize() public initializer {
    __Ownable_init();
}

Note I'm importing the contracts-ethereum-package version of Initializable, and also note I'm calling __Ownable_init(); instead of Ownable.initialize()

2 Likes

Hi @blakewest,

Thanks for sharing updated code for OpenZeppelin Contracts Ethereum Package 3.x :pray:

Contracts added the UpgradeSafe prefix in OpenZeppelin Contracts Ethereum Package v3.0.