Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignition guide for creating UUPS upgradeable module #788

Open
kanej opened this issue Jul 18, 2024 · 6 comments
Open

Ignition guide for creating UUPS upgradeable module #788

kanej opened this issue Jul 18, 2024 · 6 comments
Labels
status:ready This issue is ready to be worked on

Comments

@kanej
Copy link
Member

kanej commented Jul 18, 2024

The current upgrade-able contract docs guide is based around the TransparentUpgradeableProxy pattern:

https://hardhat.org/ignition/docs/guides/upgradeable-proxies

We should add a guide for the Universal Upgradeable Proxy Standard pattern.

See the Open Zeppelin docs for a description of the difference: https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups

@kanej kanej moved this to Todo in Hardhat Ignition Jul 18, 2024
@kanej kanej added status:ready This issue is ready to be worked on and removed status:triaging labels Jul 18, 2024
@baijunjie
Copy link

Does hardhat-ignition currently support deploying UUPS contracts? I can’t find any documentation, is there any plan to support this feature?

@kanej
Copy link
Member Author

kanej commented Jul 26, 2024

There is no explicit feature supporting UUPS, the API allows you to express contract deployments and calls.
This task is to provide documentation for how to do that.

@AddressXception
Copy link

you just need to use the generic ERC1967Proxy:

import { buildModule } from '@nomicfoundation/hardhat-ignition/modules';

const ProxyModule = buildModule('ProxyModule', (builder) => {
  // Deploy the implementation contract
  const implementation = builder.contract('MyContract');

  // Encode the initialize function call for the contract.
  const initialize = builder.encodeFunctionCall(implementation, 'initialize', [
    'param1',
    'param2',
  ]);

  // Deploy the ERC1967 Proxy, pointing to the implementation
  const proxy = builder.contract('ERC1967Proxy', [implementation, initialize]);

  return { proxy };
});

export const MyContractModule = buildModule('MyContractModule', (builder) => {
  // Get the proxy from the previous module.
  const { proxy } = builder.useModule(ProxyModule);

  // Create a contract instance using the deployed proxy's address.
  const instance = builder.contractAt('MyContract', proxy);

  return { instance, proxy };
});

export default MyContractModule;

@baijunjie
Copy link

baijunjie commented Aug 20, 2024

you just need to use the generic ERC1967Proxy:

import { buildModule } from '@nomicfoundation/hardhat-ignition/modules';

const ProxyModule = buildModule('ProxyModule', (builder) => {
  // Deploy the implementation contract
  const implementation = builder.contract('MyContract');

  // Encode the initialize function call for the contract.
  const initialize = builder.encodeFunctionCall(implementation, 'initialize', [
    'param1',
    'param2',
  ]);

  // Deploy the ERC1967 Proxy, pointing to the implementation
  const proxy = builder.contract('ERC1967Proxy', [implementation, initialize]);

  return { proxy };
});

export const MyContractModule = buildModule('MyContractModule', (builder) => {
  // Get the proxy from the previous module.
  const { proxy } = builder.useModule(ProxyModule);

  // Create a contract instance using the deployed proxy's address.
  const instance = builder.contractAt('MyContract', proxy);

  return { instance, proxy };
});

export default MyContractModule;

Thank you for providing the solution.

If my contract is inherited from @openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol, can I use this method for deployment? Or is there a specific deployment method for UUPSUpgradeable?

@2075
Copy link

2075 commented Sep 19, 2024

how would you approach an upgrade module based on this example?

@sirnicolaz
Copy link

Not sure why this issue was closed, as neither here nor in the linked issue anything was solved (meaning: how to upgrade a UUPS proxy via ignition).

I am posting my solution to the upgrade process, although I can't guarantee that's the best way to proceed.

First, find your proxy artifact (I took a screenshot of my location)

Screenshot 2024-12-04 at 11 24 01

And add this to the ABI

{
      "inputs": [
        {
          "internalType": "address",
          "name": "newImplementation",
          "type": "address"
        },
        { "internalType": "bytes", "name": "data", "type": "bytes" }
      ],
      "name": "upgradeToAndCall",
      "outputs": [],
      "stateMutability": "payable",
      "type": "function"
},

This will ensure that ignition can recognize the upgrade method during the execution.
You will have to commit your artifacts to avoid future issues.

After that, you can have an upgrade module like this:

import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
import ProxyModule from "./ProxyModule.ts"; // point it to your actual module

const MyContractModuleV2 = buildModule("MyContractModuleV2", (m) => {
  const deployer = m.getAccount(0);

  const { proxy: proxyFuture } = m.useModule(ProxyModule);

  // Fetch the callable proxy contract
  const proxy = m.contractAt("ERC1967Proxy", proxyFuture);

  // Deploy the new implementation contract
  const newImplementation = m.contract("MyContractV2"); // Replace with the upgraded contract name

  // Call the upgradeTo function on the proxy to point to the new implementation
  m.call(proxy, "upgradeToAndCall", [newImplementation, "0x"], {
    from: deployer,
  });

  return { newImplementation };
}) as ReturnType<typeof buildModule>;

export default MyContractModuleV2;

Hopefully this helps someone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:ready This issue is ready to be worked on
Projects
Status: Todo
Development

No branches or pull requests

5 participants