`upgradeProxy` sends `Upgrade And Call` tx even if bytecode has not changed


I have deployed my contracts using deployProxy and saved proxy addresses.
I am running upgradeProxy by looping though all of these proxy addresses and running this:

const options = {
      initializer: false,
      initialOwner: ....,
      constructorArgs: [...],
      redeployImplementation: 'onchange',
      verifySourceCode: false,
      kind: 'transparent'
const implementation = await ethers.getContractFactory(contractName);
proxyAddress = addressFile.getContractAddress(contractName);
const proxy = await upgrades.upgradeProxy(

I expect to not upgrade all contracts, but to first check the bytecode and if it has changed then to deploy only the changed ones (https://docs.openzeppelin.com/upgrades-plugins/1.x/#how-plugins-work)

When I run the script, looking at the explorer I see Upgrade And Call transaction for allcontracts, even if they have not changed.

Why is that?


1 Like

The redeployImplementation: 'onchange' option just means that the implementation contract will be redeployed if it was changed. So since you are running upgradeProxy multiple times without changing the implementation in between, it won't keep redeploying the same implementation to separate addresses.

But upgradeProxy always sends the tx to upgrade the proxy, regardless of what its current implementation is.


Thanks, but how can I upgrade just the implementation if its bytecode has changed?

What do you mean by upgrade just the implementation?

Proxy points to a contract. How can the proxy point to a new contract only if the new contract is different from the old one? I though this is what upgradeProxy did.

1 Like

If you want to prevent upgradeProxy from doing anything if the implementation address is not changed, you could code this into your script by comparing the implementation addresses. For example, something like:

  const newImpl = await upgrades.prepareUpgrade(proxyAddress, ContractFactory);
  if (newImpl as string !== await upgrades.erc1967.getImplementationAddress(proxyAddress)) {
    console.log('Performing upgrade');
    await upgrades.upgradeProxy(proxyAddress, ContractFactory, { redeployImplementation: 'never' });
  } else {
    console.log('Skipping upgrade');
1 Like

By doing that, I will deploy the implementation contract even if it has not changed. Can I check whether deployed contract has changed comparing to the current one?

1 Like

Thank you for this i am also facing the same problem .

I'm not sure what you mean.
If the implementation source code has not changed, then by default the Hardhat Upgrades plugin will not redeploy the implementation, even if you call prepareUpgrade.
And if you check that the implementation address has not changed, then it will not submit the transaction to upgrade the proxy.
So with what I suggested above, it should do nothing if the implementation has not changed.

Sorry, you are right, it behaves as you said. Appreciate your help. Thanks

1 Like