> ## Documentation Index
> Fetch the complete documentation index at: https://docs.peaq.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 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.

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
npm install --save-dev @openzeppelin/hardhat-upgrades
```

* Next you will need to add the following import in the `hardhat.config.js` to configure Hardhat to use this package

```jsx theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
// hardhat.config.js
...
require('@openzeppelin/hardhat-upgrades');
...
module.exports = {
...
};
```

#### 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:

```Solidity theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleStorage {
    uint256 private data;
    
    // Emitted when the stored value changes
    event ValueChanged(uint256 _data);

    function set(uint256 _data) public {
        data = _data;
        emit ValueChanged(_data);
    }

    function get() public view returns (uint256) {
        return data;
    }
}
```

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 called `upgrade_storage.js`.
* Paste the following code in the file:

```jsx theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
// scripts/upgrade_storage.js
const { ethers, upgrades } = require('hardhat');

async function main () {
  const SimpleStorage = await ethers.getContractFactory('SimpleStorage');
  console.log('Deploying SimpleStorage...');
  const simple_storage = await upgrades.deployProxy(SimpleStorage, [10], { initializer: 'store' });
  await simple_storage.waitForDeployment();
  console.log('SimpleStorage deployed to:', await simple_storage.getAddress());
}

main();
```

#### 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 the `ignition deploy`.

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
npx hardhat run --network agung scripts/upgrade_storage.js
```

* 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:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
npx hardhat console --network agung
```

* A new terminal will open up where you can execute the following the check the deployment:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
Welcome to Node.js v22.4.1.
Type ".help" for more information.
> const SimpleStorage = await ethers.getContractFactory('SimpleStorage')
undefined
> const simple_storage = await SimpleStorage.attach('0xd9b5c9Abb57175C2f4B1fE644ED0c24bF4c3c49D');
undefined
> (await simple_storage.get()).toString();
'10'
```

* 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 name `SimpleStorageV2`

```Solidity theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleStorageV2 {
    uint256 private data;
    
    // Emitted when the stored value changes
    event ValueChanged(uint256 _data);

    function set(uint256 _data) public {
        data = _data;
        emit ValueChanged(_data);
    }

    function get() public view returns (uint256) {
        return data;
    }

    // new function added
    function increment() public {
        data = data + 1;
        emit ValueChanged(data);
    }
}
```

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/` called `upgrade_storagev2`. Use the following code:

```javascript theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
// scripts/upgrade_box.js
const { ethers, upgrades } = require('hardhat');

async function main () {
  const SimpleStorageV2 = await ethers.getContractFactory('SimpleStorageV2');
  console.log('Upgrading SimpleStorage...');
  await upgrades.upgradeProxy('0xd9b5c9Abb57175C2f4B1fE644ED0c24bF4c3c49D', SimpleStorageV2);
  console.log('SimpleStorage upgraded');
}

main();
```

#### 3. Deploy upgradable contract

Again use the `run` cmd to upgrade the contract from the set network.

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
$ npx hardhat run --network agung scripts/upgrade_storagev2.js

Upgrading SimpleStorage...
SimpleStorage upgraded
```

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:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
npx hardhat console --network agung
```

Terminal will open and execute the following:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
Welcome to Node.js v22.4.1.
Type ".help" for more information.
> const SimpleStorageV2 = await ethers.getContractFactory('SimpleStorageV2');
undefined
> const simple_storage = await SimpleStorageV2.attach('0xd9b5c9Abb57175C2f4B1fE644ED0c24bF4c3c49D');
undefined
> await simple_storage.increment();
...
> (await simple_storage.get()).toString();
'11'
```

🎉 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](https://docs.openzeppelin.com/learn/upgrading-smart-contracts#how-upgrades-work).
