> For the complete documentation index, see [llms.txt](https://abc-71.gitbook.io/curriculum/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://abc-71.gitbook.io/curriculum/week-7/uups-proxy-example.md).

# UUPS Proxy Example

Let us dive into the UUPS (Universal Upgradeable Proxy Standard) proxy pattern with a practical example. This will allow us to create upgradeable smart contracts while minimizing gas costs and maintaining a clear separation between your contract logic and storage.

## What is UUPS Proxy?

UUPS is an upgradeable proxy pattern that leverages a single implementation contract and a proxy to delegate calls to the implementation. The proxy holds the state, while the implementation contract contains the logic. UUPS allows the implementation to be upgraded through a function call on the proxy itself, reducing gas costs compared to other patterns like Transparent Proxies.

#### Key Components

1. **Proxy Contract**: This is the contract that users interact with. It holds the state and delegates calls to the implementation.
2. **Implementation Contract**: This contains the actual logic of the contract. It can be upgraded by deploying a new version and pointing the proxy to the new implementation.
3. **Admin Functionality**: The proxy needs to have a way to authorize upgrades.

## UUPS Proxy Implementation

### **Step 1: Set Up Your Project**

First, make sure you have a working environment with **Node.js**, **Hardhat**, and **OpenZeppelin**:

```bash
mkdir UUPSExample
cd UUPSExample
npm init -y
npm install --save-dev hardhat
npm install @openzeppelin/contracts
```

### **Step 2: Create the Implementation Contract**

```bash
npx hardhat
```

Create a file named `MyContract.sol` in the `contracts` folder:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyContract is UUPSUpgradeable, Ownable {
    uint256 public value;

    function initialize(uint256 initialValue) public initializer {
        value = initialValue;
    }

    function setValue(uint256 newValue) public onlyOwner {
        value = newValue;
    }

    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
```

#### **Explanation**:

* The contract uses `UUPSUpgradeable` for the upgrade mechanism.
* The `initialize` function sets the initial state.
* The `_authorizeUpgrade` function restricts who can upgrade the contract to the owner.

### **Step 4: Create the Proxy Contract**

With UUPS, the proxy is automatically handled by OpenZeppelin, so you don't need to create a separate proxy contract manually. Instead, you will deploy the implementation contract and interact with it via the proxy mechanism.

### **Step 5: Write the Deployment Script**

In the `scripts` folder, create a file named `deploy.js`:

```javascript
async function main() {
    const MyContract = await ethers.getContractFactory("MyContract");
    const myContract = await MyContract.deploy();
    await myContract.deployed();

    console.log("MyContract deployed to:", myContract.address);

    // Initialize the contract
    const tx = await myContract.initialize(42);
    await tx.wait();

    console.log("Contract initialized with value:", 42);
}

main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });
```

### **Step 6: Deploy the Contract**

Run the deployment script:

```bash
npx hardhat run scripts/deploy.js --network <your_network>
```

### **Step 7: Upgrade the Contract**

Let’s say you want to add new functionality in the future. Create a new version of your contract. Create `MyContractV2.sol`:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./MyContract.sol";

contract MyContractV2 is MyContract {
    function incrementValue() public {
        value += 1;
    }
}
```

#### **Explanation**:

* This version extends `MyContract` and adds a new function `incrementValue`.

### **Step 8: Deploy the New Implementation**

In the `scripts` folder, create a new script named `upgrade.js`:

```javascript
async function main() {
    const myContractAddress = "YOUR_CONTRACT_ADDRESS"; // replace with your deployed contract address
    const MyContractV2 = await ethers.getContractFactory("MyContractV2");
    const myContractV2 = await MyContractV2.deploy();

    await myContractV2.deployed();
    console.log("MyContractV2 deployed to:", myContractV2.address);

    const myContract = await ethers.getContractAt("MyContract", myContractAddress);
    const tx = await myContract.upgradeTo(myContractV2.address);
    await tx.wait();

    console.log("Upgraded to MyContractV2");
}

main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });
```

### **Step 9: Upgrade Your Contract**

Run the upgrade script:

```bash
npx hardhat run scripts/upgrade.js --network <your_network>
```

### Step 10: Interact with the Upgraded Contract

You can now call the new `incrementValue` function on the upgraded contract. Create a script named `interact.js`:

```javascript
async function main() {
    const myContractAddress = "YOUR_CONTRACT_ADDRESS"; // replace with your deployed contract address
    const myContract = await ethers.getContractAt("MyContract", myContractAddress);

    // Call incrementValue
    const tx = await myContract.incrementValue();
    await tx.wait();

    const newValue = await myContract.value();
    console.log("New value after increment:", newValue.toString());
}

main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });
```

Run the interaction script:

```bash
npx hardhat run scripts/interact.js --network sepolia
```

You’ve successfully implemented a UUPS proxy pattern for upgradeable contracts! Here’s a recap of what we did:

1. **Created an implementation contract** with upgradeable functionality.
2. **Deployed the contract** to the network.
3. **Added a new version** of the contract with additional features.
4. **Upgraded the contract** to the new implementation.
5. **Interacted with the upgraded contract** to demonstrate its new capabilities.

This UUPS pattern provides a flexible way to maintain and upgrade your smart contracts while optimizing for gas costs, making it an ideal choice for modern Ethereum development.
