Upgradable Smart Contracts
Smart contracts are immutable by nature, meaning their code cannot be altered after deployment. While this immutability ensures security and trust in a blockchain, it also presents challenges when you need to fix bugs, add new features, or adapt to evolving regulations. Upgradable smart contracts address these challenges by allowing developers to update the logic of a deployed contract without affecting its state or address.
This guide will show you how to build and deploy upgradable smart contracts using OpenZeppelin’s Upgrades Plugin and Hardhat for deployment.
Prerequisites
- You have followed the previous tutorials and are confident on learning about new contract types.
- You have an understanding on how to deploy contracts using Hardhat.
- JavaScript programming language experience.
- Understanding about upgradable smart contracts.
Why Upgradable Smart Contracts?
Traditional smart contracts are inherently limited in flexibility. Once deployed, they are immutable pieces of code residing on the blockchain. Only the state of the contract can change while the code itself remains fixed. This means that if bugs are discovered or if improvements are needed, you’re left without an option to update the contract.
Upgradable smart contracts address this limitation by offering flexibility and adaptability throughout the contract’s lifecycle. They allow for seamless bug fixes and security patches on a deployed contract, helping to mitigate vulnerabilities and address security concerns. In an ever-evolving blockchain environment—where best practices and regulatory standards are continuously being redefined—using upgradable smart contracts enables you to update your code to comply with new regulations, ultimately facilitating broader adoption.
Instructions
Building an Upgradable Smart Contract
For the creation of the upgradable smart contract we will be using OpenZeppelin’s deployProxy
plugin.
1. Install upgrades plugin
- After creating a Hardhat environment you will need to download the OpenZeppelin package that contains the upgrade logic.
- Next you will need to add the following import in the
hardhat.config.js
to configure Hardhat to use this package
2. Create the contract
Now we need to create the contract that will be upgradable. For simplicity sake, let us again use the SimpleStorage.sol
contract from before. Please place this file in the /contracts
directory of your project. The code is as follows:
Please note how we added an event which will be helpful later.
3. Write the deployment script
Next, we need to deploy the contract as upgradable. This uses a bit different logic so please make sure to take special note on the code below. Rather than putting the deployment script in the ignition/modules/ directory path, we place it in the scripts/.
- Create a new file in the
/scripts
directory calledupgrade_storage.js
. - Paste the following code in the file:
4. Deploy the contract
- Run the following cmd to deploy the contract. For the upgradable contract we use the
npx hardhat run
cmd instead of theignition deploy
.
- After successfully doing so, the deployed contract address will be displayed. Save this value so you can access the contract in the future.
5. Interact the contract
- Hardhat console will be used to interact with the smart contract we have deployed. To launch the console you can run the cmd:
- A new terminal will open up where you can execute the following the check the deployment:
- Confirms that the contract has been properly stored an initialized at
10
.
Upgrade previously deployed contract
Let us say down the line, we want to upgrade this smart contract to have a new feature - increment the stored value.
1. Create a new contract
- Create a new Solidity contract in the
contracts/
directory with the nameSimpleStorageV2
Take special note how to contract is exactly the same, except for the name of the contract and the new increment function that was added.
2. Upgrade previously deployed contract
Use the updateProxy
function from OpenZeppelin to update the contract,
- Create a new file at
scripts/
calledupgrade_storagev2
. Use the following code:
3. Deploy upgradable contract
Again use the run
cmd to upgrade the contract from the set network.
The above will be displayed on a successful upgrade. The code have been updated to the latest version, while maintaining the same address and state from before.
4. Interact with the contract
Again, let us use the Hardhat console to interact with the contract. Notice how we are able to call increment()
that we added in our update. Launch the console:
Terminal will open and execute the following:
🎉 Congratulations! You have created a smart contract and successfully upgraded it. Notice how the address and the stayed stayed the same, until the increment() function was called. Now you have more flexibility when dealing with your smart contracts. If you would like to learn more about how these updates work, please checkout the OpenZeppelin documentation.