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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://abc-71.gitbook.io/curriculum/week-7/uups-proxy-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
