Specifying an initializer to be called in proposeUpgrade

:1234: Code to reproduce

I have an existing contract which I need to upgrade to a newer version. This newer version has its own new initializer method called initializeV2 which initialises some new stuff.

How do I call proposeUpgrade while also specifying this initialization to happen?

eg: upgradeProxy has a call key which can be used for this:

      await upgrades.upgradeProxy(tokenV1, TokenV2, {
        kind: "uups",
        call: {
          fn: "initializeV2",
          args: [],
        },
      });

But I see no such option in proposeUpgrade :frowning:

1 Like

The ability to call a function with an upgrade seems to be missing from the underlying Defender APIs. I will try to confirm this. As a workaround you may need to create the Admin proposal manually, apologies.

1 Like

Ah that's unfortunate.

As a workaround you may need to create the Admin proposal manually

Would this mean:

  1. Use prepareUpgrade instead of proposeUpgrade to deploy the new implementation contract.
  2. Goto defender UI -> goto proxy contract -> new proposal -> admin action -> upgradeToAndCall with the new implentation address from point #1 and the data argument encoding the new initializeV2 function to be called?

Note: The new proposal -> upgrade screen doesn't have the option to call a function either.

Hey @hmm -

Unfortunately this is a gap as of now. The Defender Upgrade functionality assumes the upgrade as a standalone call.

If feasible, you could treat these as two different calls (propose upgrade and then create an admin action for this initializer).

As you mention, one possible alternative would be to submit the upgrade through the Defender UI using an Admin Action with upgradeToAndCall. One note here is that Defender typically stores the ABI of the implementation contract (which would not include this upgradeToAndCall function) but you could add it manually.

1 Like

Mine is a UUPS contract so the upgradeToAndCall function exists on the implementation contract. Only the tiny minor annoyance of encoding the function to be called but its not a big deal.

If feasible, you could treat these as two different calls (propose upgrade and then create an admin action for this initializer).

This also works :smiley:
But I'm just worried about possible security issues. eg. implementation gets updated but the initialiser call gets frontrunned by some transaction which can misuse the uninitialized state. Using the upgradeToAndCall directly felt safer to me!

Yes preferably you should upgrade and initialize atomically.

1 Like