DEV Community

Abhik Banerjee
Abhik Banerjee

Posted on

Deploying Your Upgradeable Smart Contract in 5 minutes

Deployment is the final step in the smart contract development journey. It’s like the concept of Valhalla – only the rigorously tested contracts are deployed (we all know what happens otherwise). This is the third article in my series of Upgradeable Smart Contracts: End-to-End and in this article, we shall explore how you can easily deploy a contract and then upgrade it to a higher version. The time limit is 5 minutes and I would hate for the article to run too long so let’s get going…

Housekeeping

Before we deploy the contracts, please note that these contracts have been discussed in detail in the first article of this series. The second article showed how to test them out. So, this one assumes that you have prior knowledge of the topics discussed in the previous articles. We will be deploying to Polygon’s Mumbai Testnet in this article. If you are new to blockchain development, just know that deploying to other chains is as easy as changing an URL in the hardhat.config.js or the .env file.

The code files for this tutorial series are open-sourced at the GitHub Repo below:

GitHub logo abhik-99 / Upgradeable-Smart-Contracts-Blog

This is the repo containing code for my blog series on Upgradeable Smart Contracts.

Advanced Sample Hardhat Project

This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the ecosystem.

The project comes with a sample contract, a test for that contract, a sample script that deploys that contract, and an example of a task implementation, which simply lists the available accounts. It also comes with a variety of other tools, preconfigured to work with the project code.

Try running some of the following tasks:

npx hardhat accounts
npx hardhat compile
npx hardhat clean
npx hardhat test
npx hardhat node
npx hardhat help
REPORT_GAS=true npx hardhat test
npx hardhat coverage
npx hardhat run scripts/deploy.js
node scripts/deploy.js
npx eslint '**/*.js'
npx eslint '**/*.js' --fix
npx prettier '**/*.{json,sol,md}' --check
npx prettier '**/*.{json,sol,md}' --write
npx solhint 'contracts/**/*.sol'
npx solhint 'contracts/**/*.sol' --fix
Enter fullscreen mode Exit fullscreen mode

Etherscan verification

To try out Etherscan verification, you…

Deploying v1

Deploying the first version of the contract is fairly easy. We just need to run npx hardhat run to run the deploy_v1.js script. This script contains the steps to deploy the contract as shown below:

const { ethers, upgrades } = require("hardhat");

async function main() {
  const Contract = await ethers.getContractFactory("OurUpgradeableNFT1");
  const contract = await upgrades.deployProxy(
    Contract,
    ["Hello Many Worlds!"],
    {initializer: 'initialize', kind: 'uups'}
    );

  await contract.deployed();
  console.log("OurUpgradeableNFT1 deployed to:", contract.address);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Enter fullscreen mode Exit fullscreen mode

In the above code, inside the main function, we first get a reference to the contract OurUpgradeableNFT1 using the getContractFactory() method in the ethers exposed by Hardhat. The next line is a bit different because it is an upgradable smart contract. Normally we could just invoke .deploy() with the constructor arguments on the contract instance. But here upgrades.deployProxy() is needed to deploy the Proxy as well as the implementation contract behind the proxy. Note that the address that will be logged in the console will be the address of the proxy contract.

Proxy Verification

We can obtain the address of the implementation contract by looking up the transactions from our wallet address in the concerned blockchain explorer. In this case, it would be Polygonscan but on Mumbai Testnet.

The easier method is proxy contract verification. Once the contracts are deployed, we need to browse to the Proxy Contract as shown below.

Proxy Contract

On the screen above, click on** More Options** and then select Is this a proxy?. This should open a screen similar to the one below.

Proxy Contract Verification

In the screen above, you will notice the address of the proxy contract and an option to Verify. Click on the Verify Button. This will prompt the proxy verification process which on completion would show a dialog like the one below. This dialog will contain the address of the implementation contract.

Proxy Contract Verified

Verifying Implementation

Once the Proxy verification is complete, the “Read as Proxy” and “Write as Proxy” options will appear when you browse over to the Proxy Contract on the explorer again. At this point, we need to complete verification of the implementation contract behind the proxy. Even the proxy contract will notify that the implementation is not verified.

Verification of the Implementation Smart Contract is also a bit different. Keep in mind that this version of our contract takes in a greeting (an arbitrary string value) when deploying as shown in the deployment code above. So, you might think that you need to pass in that string as that is normally done. The picture below will be similar to the output you receive if you do that.

Complete Steps

In the image above, you see what happens when you try to pass in the initializer arguments as constructor arguments. This is another point that differentiates the two functions. Thus, verifying upgradeable smart contracts is that much easier. You just need to pass in the address as shown above that will verify the implementation.

Proxy vs Implementation

Once the verification above is completed, just browse over to the Proxy contract again. At this point, you will notice that the greeting is recorded and the owner is pointing to the deploying wallet address as shown below.

Proxy contract after v1 verification

If you browse over to the implementation contract, you will notice that the owner is recorded as the 0x0 address and the greeting is noted as empty. This again shows that the implementation contract is pure logic. The context is handled by the proxy contract. The image below shows that.

Verified v1 Implementation

Deploying v2

Next let’s upgrade our smart contract to version 2. The code below will be run to do that. We will be using npx hardhat run again, deploy the OurUpgradeableNFT2 contract and then make the proxy point to this contract version.

const { ethers, upgrades } = require("hardhat");

const PROXY_ADDRESS = "0xD1a7c6f15ecC1ceD1219CDa8F556026ADB2063ad"; //Address of version 1
const VERSION1 = "0x35C9fC0433A007E85E1df9339916F703D2c7512F"; //Address of the version 1 implementation

async function main() {
  const Contract = await ethers.getContractFactory("OurUpgradeableNFT2");
  await upgrades.upgradeProxy(
    PROXY_ADDRESS,
    Contract,
    {
      call: {fn: 'reInitialize'},
      kind: "uups"
    }
    );
  console.log("Version 2 deployed.");
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Enter fullscreen mode Exit fullscreen mode

In the code above, we get the reference to OurUpgradeableNFT2 contract and then pass in the Proxy contract address along with the OurUpgradeableNFT2 contract reference and the function to call as initializer during this upgrade. The kind argument says that we would like this to be a UUPS type proxy upgrade.

Once the deploy script finishes running, if you head over to the Proxy contract address on the explorer, you will notice that the implementation contract address would have changed. Something similar to the image below will be shown. Notice we do not need to verify the Proxy contract again.

Proxy after v2 deployment

Verifying Version 2 Implementation

Verifying the upgraded smart contract is as simple as the first one. Running npx hardhat verify and passing in the address of the implementation contract will do as shown below:

deploying upgradeable smart contracts

Once the verification completes, browse over to the second implementation contract as shown below.

v2 implementation

Next move over to the Read Contract tab and you will notice that this implementation contains our required contract methods. It also contains the methods from our previous contract.

Methods in the v2 implementation

The proxy contract now points to the new implementation contract i.e., OurUpgradeableNFT2. You can head over to the proxy contract to see for yourself. You should get something similar to the image below where all the new methods are listed and it should say that the new implementation is the address where OurUpgradeableNFT2 was deployed.

Updated Proxy

As you can see from the picture above, it also says the previously recorded implementation was the address where OurUpgradeableNFT1 was deployed. Compare the picture of the proxy contract above to the one in the version 1 section.

Using Upgradeable Smart Contracts

To invoke functions in the upgradeable smart contract, you need to pass in the Proxy Contract address with the ABI of the current implementation contract. This means that the ABI need to be updated on the frontend with every upgrade. The proxy contract is given the data and the methods to invoke which it then forwards to the implementation contract.

That’s all for this one, folks!

This brings us to the end of this article. In this article, we went through the steps to deploy an upgradeable smart contract, verify the proxy and the contract and then to upgrade the implementation contract to a newer version.

In the next article in this series, we shall discuss the nuances of upgradeable smart contracts. It would basically recap the essential steps and add a few pointers to help you better and more securely use upgradeable smart contracts.

If you think I might have missed something, feel free to add a comment below. If you liked the article leave some love on the article and feel free to share it. Reach out to me if you have any topic recommendations. Until the next one, continue to build awesome stuff on Web3 and WAGMI!

Top comments (0)