After upgrade using prepareUpgrade() with Gnosis Safe MyContract.address returns the imp. address

I’ve just upgraded contracts using prepareUpgrade() :

const existingContract = await MyContract.deployed();
//const newContract = await upgradeProxy(existingContract.address, MyContract, { deployer });
const newContract = await prepareUpgrade(existingContract.address, MyContract, { deployer });

Afterwards I upgraded the contracts on Gnosis Safe. Checking ProxyAdmin on Etherscan all looks correct, the proxy contract points to the new implementation contract. However, when I on the console MyContract.address I get the address of the implementation address where I would expect to get the proxy address. Hence, when calling MyContract.deployed() I don’t get the address of the proxy. Any idea?

I am using migration scripts calling MyContract.deployed() for some initial set-ups.

I am using the same contract name ‘MyContract’ for the old and the new version (not like Box and BoxV2).

From the code lines you’ve posted, would existingContract.address, give you the proxy? Or is that your old implementation address?

In my upgrade script, from the tutorial I followed in OpenZeppelin Upgrades: Step by Step Tutorial for Hardhat

I have this

async function main() {
    const proxyAddress = '0xC031c8F6C360E18b232F4728b336AA6394668F48';    // CHANGEIT - change this to your PROXY address, not impl, not timelock, PROXY

    const catnipUpdate = await ethers.getContractFactory("Catnip");
    console.log("Preparing upgrade...");
    const catnipUpdateAddress = await upgrades.prepareUpgrade(proxyAddress, catnipUpdate);
    console.log("catnipUpdateAddress at:", catnipUpdateAddress);

You may have to deploy with some arguments, but the first address is the proxyAddress, which would be your existingContract.address

Thank you very much @Tsushima_Yoshiko, for your post.
Yes, I assume that existingContract.address gives me back the proxy address of MyContract.

I follow the tutorial

What I don’t understand is, why MyContract.deployed() first returns the proxy address and after the upgrade the new implementation address.

Moreover, before using Gnosis Safe, I did the upgrade as follows:

const newContract = await upgradeProxy(existingContract.address, MyContract, { deployer });

That worked as expected. Querying the ProxyAdmin (on Etherscan) getProxyImplementation(proxyAddress) I get the correct implementation address.

Here the code of 1_DeployOrUpgrade.js:

const Migrations = artifacts.require("Migrations");
const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');
const { admin } = require('@openzeppelin/truffle-upgrades');
const { prepareUpgrade } = require('@openzeppelin/truffle-upgrades');
const argv = require('minimist')(process.argv.slice(2), {string: ['operation']});

const MyContract = artifacts.require("MyContract");

module.exports = async function (deployer, network) {
  var operation = argv['operation'];
  await deployer.deploy(Migrations);
  switch(operation) {
    case 'deploy':
      const myContract = await deployProxy(MyContract, { deployer});
      const myContractProxyAddress = myContract.address;
      console.log('Deployed ', myContractProxyAddress);
    case 'upgrade':
      var gnosisSafe;
      switch(network) {
        case 'rinkeby':
          gnosisSafe = '0x97826de55402165A9c317E30e53CF65BE75226B9';
          await admin.transferProxyAdminOwnership(gnosisSafe);
      if(MyContract.isDeployed() ) {
        const existingMyContract = await MyContract.deployed();
        //const newMyContract = await upgradeProxy(existingMyContract.address, MyContract, { deployer });
        const newMyContract = await prepareUpgrade(existingMyContract.address, MyContract, { deployer });
        console.log('Upgraded ', newMyContract.address);

      } else {
        console.log("Not upgraded. Not all required contracts are deployed: ");
        console.log("MyContract: ", MyContract.isDeployed());
      console.log("Operation unknown.");

In the MyContract.json under
“networks”.“4”.“address:” now is the address of the implementation contract, before it was the address of the proxy contract. I guess MyContract.deployed() reads the address from there.

Here the package versions:

├─┬ @openzeppelin/truffle-upgrades@1.5.0

│ ├── @openzeppelin/upgrades-core@1.5.1

│ ├── @truffle/contract@4.3.13

│ └── solidity-ast@0.4.19

I can reproduce this scenario on the dev network.

Hi @Homer,

OpenZeppelin Upgrades Plugins store the proxy address in the Truffle artifacts of the first implementation contract using myContract.deployed(). I assume that when you do a prepare upgrade you then get the implementation address using myContract.deployed() in the artifacts.

You can use[Address of the proxy]) to interact via the console.

1 Like

Thank you very much @abcoathup, once more for your help.

So there is no other way to retrieve the proxy addresses after a prepareUpgrade() than using hard coded proxy addresses, right?

1 Like

Hi @homer,

Yes, please see the following comment on GitHub for the design decision:

1 Like