hardhat icon indicating copy to clipboard operation
hardhat copied to clipboard

Testing ignition modules missing temporary artifacts for properly testing upgrades

Open daveroga opened this issue 7 months ago • 1 comments

Version of Hardhat

2.23.0

What happened?

Following the same approach explained here in Hardhat documentation for upgrading proxy and testing https://hardhat.org/ignition/docs/guides/upgradeable-proxies produces different addresses for proxy after upgrading instead of upgrading previous deployed one in same test.

Minimal reproduction steps

You will see in this test that proxy has changed the address between deployment and upgrade. It should reuse the same deployed proxy and upgrade it, so we can check state is the same in a proxy contract after upgrading. In real deployment and upgrade is working with same proxy address. Maybe is due to missing journal and artifacts while testing but it should work the same as in real deployment so we can test ignition modules properly in tests.


import DemoModule from "../ignition/modules/ProxyModule";
import UpgradeModule from "../ignition/modules/UpgradeModule";

describe("Demo Proxy", function () {
  describe("Upgrading", function () {
    it("Should have upgraded the proxy to DemoV2", async function () {
      const [, otherAccount] = await ethers.getSigners();
      const { demo } = await ignition.deploy(DemoModule,);

      console.log("Proxy Demo address: ", await demo.getAddress());
      expect(await demo.connect(otherAccount).version()).to.equal("1.0.0");

      const { demo2 } = await ignition.deploy(UpgradeModule);

      console.log("Proxy Demo address after upgrade: ", await demo2.getAddress());
      expect(await demo2.connect(otherAccount).version()).to.equal("2.0.0");
      expect(await demo2.connect(otherAccount).name()).to.equal("Example Name");
    });
  });
});

Search terms

No response

daveroga avatar May 06 '25 10:05 daveroga

Hi @daveroga, thanks for opening the issue!

This is the intended design for Hardhat Ignition, to allow users to be as declarative as they want with their deployment modules, but I could see how this might be unintuitive at first glance. We'll discuss internally about whether this is something we would want to potentially add as a feature to Ignition at some point.

Additionally, the example project isn't necessarily built to be a drop in real world example, but more of a showcase of how you could set up common scenarios for proxy development to make it easier to plug the pieces into your own project. For instance, if you wanted to achieve the situation you're describing, you could do so with a couple edits to the project modules and test:

// Edits to "DemoModule" inside ignition/modules/ProxyModule.ts
const demoModule = buildModule('DemoModule', (m) => {
  const { proxy, proxyAdmin } = m.useModule(proxyModule)

  const demo = m.contractAt('Demo', proxy)

  return { demo, proxyAdmin }
})
// Edits to "UpgradeModule" inside ignition/modules/UpgradeModule.ts
const upgradeModule = buildModule('UpgradeModule', (m) => {
  const proxyAddress = m.getParameter('proxyAddress')
  const proxyAdminAddress = m.getParameter('proxyAdminAddress')
  const proxyAdminOwner = m.getAccount(0)

  const proxy = m.contractAt('TransparentUpgradeableProxy', proxyAddress)
  const proxyAdmin = m.contractAt('ProxyAdmin', proxyAdminAddress)

  const demoV2 = m.contract('DemoV2')

  const encodedFunctionCall = m.encodeFunctionCall(demoV2, 'setName', [
    'Example Name',
  ])

  m.call(proxyAdmin, 'upgradeAndCall', [proxy, demoV2, encodedFunctionCall], {
    from: proxyAdminOwner,
  })

  return { proxyAdmin, proxy }
})
// test/ProxyDemo.ts
describe('Demo Proxy', function () {
  describe('Upgrading', function () {
    it('Should have upgraded the proxy to DemoV2', async function () {
      const [, otherAccount] = await ethers.getSigners()
      const { demo, proxyAdmin } = await ignition.deploy(DemoModule)

      const demoAddress = await demo.getAddress()

      console.log('Proxy Demo address: ', demoAddress)
      expect(await demo.connect(otherAccount).version()).to.equal('1.0.0')

      const { demo: demo2 } = await ignition.deploy(UpgradeModule, {
        parameters: {
          UpgradeModule: {
            proxyAddress: await demo.getAddress(),
            proxyAdminAddress: await proxyAdmin.getAddress(),
          },
        },
      })

      const demo2Address = await demo2.getAddress()

      console.log('Proxy Demo address after upgrade: ', demo2Address)
      expect(await demo2.connect(otherAccount).version()).to.equal('2.0.0')
      expect(await demo2.connect(otherAccount).name()).to.equal('Example Name')
      expect(demo2Address).to.equal(demoAddress)
    })
  })
})

zoeyTM avatar Jun 06 '25 08:06 zoeyTM