# How to implement UUPS with a solidity contract having VRF and automation features?

**URL:** <https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913>\
**Category:** Contracts\
**Created:** [June 24, 2024, 7:11pm UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913 "2024-06-24T19:11:19Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mehdi\_El\_Filahi](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/mehdi_el_filahi/32/21137_2.png) [@Mehdi\_El\_Filahi](https://forum.openzeppelin.com/u/Mehdi_El_Filahi)\
**Post date:** [June 24, 2024, 7:11pm UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/1 "2024-06-24T19:11:19Z")

</div>

I am developping a solidity contract with those inheritances:

- ERC20
- ERC20FlashMint
- VRFConsumerBaseV2Plus
- AutomationCompatibleInterface

```auto
pragma solidity ^0.8.24;

import "@chainlink/contracts/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import "@chainlink/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol";
import "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol";

contract ExampleV1 is ERC20, ERC20FlashMint, VRFConsumerBaseV2Plus, AutomationCompatibleInterface {
...
}

```

I also created a javascript Test file to be able to deploy and simulate all the functions calls of the contract.

I would like to be able to create a new contract ExampleV2 but i struggle to add UUPS capability of Openzeppelin.

```auto
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

```

If i try to add them into the contract ExampleV1, i get a lot of conflicts telling me that functions exist more than once.

Can someone help me understand how to create a proxy contract with UUPS that will help me upgrade the ExampleV1 to ExampleV2 and also add the code in Javascript to be able to have a complete test in Hardhat deploying first the ExampleV1 and then the ExampleV2.

Thank you for your help.

If needed more information. I would be happy to add details.

**Expected result would be:**

Develop ExampleV1 (upgradeable)

In the javascript test code:

- deploy ExampleV1
- call ExampleV1 functions

Develop ExampleV2 (upgrdeable)

In the javascript test code:

- deploy ExampleV1
- call ExampleV1 functions
- In the same address deploy ExampleV2
- call ExampleV2 functions

---

<div class="post-metadata">

**Author:** ![Amxx](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/amxx/32/668_2.png) [@Amxx](https://forum.openzeppelin.com/u/Amxx)\
**Post date:** [June 25, 2024, 1:16pm UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/2 "2024-06-25T13:16:42Z")

</div>

Hello @Mehdi_El_Filahi

Is your V1 already deployed? If yes, can you share the address?

The first thing that comes to mind is that there is no process to upgrade from a non-upgradeable to an upgradeable contract. Upgradeability requires the use of a proxy, and the non upgradeable contracts are not designed to work with a proxy.

If you are in a situation where you deployed a non-upgradeable contract in the past, and you now want to upgrade it ... that is just not possible.

---

<div class="post-metadata">

**Author:** ![Amxx](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/amxx/32/668_2.png) [@Amxx](https://forum.openzeppelin.com/u/Amxx)\
**Post date:** [June 25, 2024, 1:17pm UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/3 "2024-06-25T13:17:26Z")

</div>

> [@Mehdi\_El\_Filahi](#):
>
> In the same address deploy ExampleV2

This is not how ethereum works. You just cannot do that.

---

<div class="post-metadata">

**Author:** ![Mehdi\_El\_Filahi](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/mehdi_el_filahi/32/21137_2.png) [@Mehdi\_El\_Filahi](https://forum.openzeppelin.com/u/Mehdi_El_Filahi)\
**Post date:** [June 25, 2024, 3:01pm UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/4 "2024-06-25T15:01:24Z")

</div>

Hi Amxx,

For the moment we did not deploy on a testnet but only tested with Hardhat because we are stil in development.

I will show an example of the solidity contract that we try to change to be upgradeable.

---

<div class="post-metadata">

**Author:** ![Mehdi\_El\_Filahi](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/mehdi_el_filahi/32/21137_2.png) [@Mehdi\_El\_Filahi](https://forum.openzeppelin.com/u/Mehdi_El_Filahi)\
**Post date:** [June 26, 2024, 7:50am UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/5 "2024-06-26T07:50:17Z")

</div>

@Amxx here is an example of contract similar to ours that i would like to convert as upgradeable.

If you would guide me of help me it would be really reallt great.

Tank you.

This is an example from Patrick Collins ([https://github.com/PatrickAlphaC/hardhat-smartcontract-lottery-fcc/raw/62463b07955caa5cc68d027a7668d5a1372f795c/contracts/Raffle.sol](https://github.com/PatrickAlphaC/hardhat-smartcontract-lottery-fcc/raw/62463b07955caa5cc68d027a7668d5a1372f795c/contracts/Raffle.sol)):

```auto
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol";
// In the video, we use the following import statement, but newer versions of the Chainlink
// contracts have a different file structure.
// import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol";
import "hardhat/console.sol";

/* Errors */
error Raffle__UpkeepNotNeeded(uint256 currentBalance, uint256 numPlayers, uint256 raffleState);
error Raffle__TransferFailed();
error Raffle__SendMoreToEnterRaffle();
error Raffle__RaffleNotOpen();

/**
 * @title A sample Raffle Contract
 * @author Patrick Collins
 * @notice This contract is for creating a sample raffle contract
 * @dev This implements the Chainlink VRF Version 2
 */
contract Raffle is VRFConsumerBaseV2, AutomationCompatibleInterface {
    /* Type declarations */
    enum RaffleState {
        OPEN,
        CALCULATING
    }
    /* State variables */
    // Chainlink VRF Variables

    VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
    uint64 private immutable i_subscriptionId;
    bytes32 private immutable i_gasLane;
    uint32 private immutable i_callbackGasLimit;
    uint16 private constant REQUEST_CONFIRMATIONS = 3;
    uint32 private constant NUM_WORDS = 1;

    // Lottery Variables
    uint256 private immutable i_interval;
    uint256 private immutable i_entranceFee;
    uint256 private s_lastTimeStamp;
    address private s_recentWinner;
    address payable[] private s_players;
    RaffleState private s_raffleState;

    /* Events */
    event RequestedRaffleWinner(uint256 indexed requestId);
    event RaffleEnter(address indexed player);
    event WinnerPicked(address indexed player);

    /* Functions */
    constructor(
        address vrfCoordinatorV2,
        uint64 subscriptionId,
        bytes32 gasLane, // keyHash
        uint256 interval,
        uint256 entranceFee,
        uint32 callbackGasLimit
    ) VRFConsumerBaseV2(vrfCoordinatorV2) {
        i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
        i_gasLane = gasLane;
        i_interval = interval;
        i_subscriptionId = subscriptionId;
        i_entranceFee = entranceFee;
        s_raffleState = RaffleState.OPEN;
        s_lastTimeStamp = block.timestamp;
        i_callbackGasLimit = callbackGasLimit;
    }

    function enterRaffle() public payable {
        // require(msg.value >= i_entranceFee, "Not enough value sent");
        // require(s_raffleState == RaffleState.OPEN, "Raffle is not open");
        if (msg.value < i_entranceFee) {
            revert Raffle__SendMoreToEnterRaffle();
        }
        if (s_raffleState != RaffleState.OPEN) {
            revert Raffle__RaffleNotOpen();
        }
        s_players.push(payable(msg.sender));
        // Emit an event when we update a dynamic array or mapping
        // Named events with the function name reversed
        emit RaffleEnter(msg.sender);
    }

    /**
     * @dev This is the function that the Chainlink Keeper nodes call
     * they look for `upkeepNeeded` to return True.
     * the following should be true for this to return true:
     * 1. The time interval has passed between raffle runs.
     * 2. The lottery is open.
     * 3. The contract has ETH.
     * 4. Implicity, your subscription is funded with LINK.
     */
    function checkUpkeep(bytes memory /* checkData */ )
        public
        view
        override
        returns (bool upkeepNeeded, bytes memory /* performData */ )
    {
        bool isOpen = RaffleState.OPEN == s_raffleState;
        bool timePassed = ((block.timestamp - s_lastTimeStamp) > i_interval);
        bool hasPlayers = s_players.length > 0;
        bool hasBalance = address(this).balance > 0;
        upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers);
        return (upkeepNeeded, "0x0"); // can we comment this out?
    }

    /**
     * @dev Once `checkUpkeep` is returning `true`, this function is called
     * and it kicks off a Chainlink VRF call to get a random winner.
     */
    function performUpkeep(bytes calldata /* performData */ ) external override {
        (bool upkeepNeeded,) = checkUpkeep("");
        // require(upkeepNeeded, "Upkeep not needed");
        if (!upkeepNeeded) {
            revert Raffle__UpkeepNotNeeded(address(this).balance, s_players.length, uint256(s_raffleState));
        }
        s_raffleState = RaffleState.CALCULATING;
        uint256 requestId = i_vrfCoordinator.requestRandomWords(
            i_gasLane, i_subscriptionId, REQUEST_CONFIRMATIONS, i_callbackGasLimit, NUM_WORDS
        );
        // Quiz... is this redundant?
        emit RequestedRaffleWinner(requestId);
    }

    /**
     * @dev This is the function that Chainlink VRF node
     * calls to send the money to the random winner.
     */
    function fulfillRandomWords(uint256, /* requestId */ uint256[] memory randomWords) internal override {
        // s_players size 10
        // randomNumber 202
        // 202 % 10 ? what's doesn't divide evenly into 202?
        // 20 * 10 = 200
        // 2
        // 202 % 10 = 2
        uint256 indexOfWinner = randomWords[0] % s_players.length;
        address payable recentWinner = s_players[indexOfWinner];
        s_recentWinner = recentWinner;
        s_players = new address payable[](0);
        s_raffleState = RaffleState.OPEN;
        s_lastTimeStamp = block.timestamp;
        (bool success,) = recentWinner.call{value: address(this).balance}("");
        // require(success, "Transfer failed");
        if (!success) {
            revert Raffle__TransferFailed();
        }
        emit WinnerPicked(recentWinner);
    }

    /**
     * Getter Functions
     */
    function getRaffleState() public view returns (RaffleState) {
        return s_raffleState;
    }

    function getNumWords() public pure returns (uint256) {
        return NUM_WORDS;
    }

    function getRequestConfirmations() public pure returns (uint256) {
        return REQUEST_CONFIRMATIONS;
    }

    function getRecentWinner() public view returns (address) {
        return s_recentWinner;
    }

    function getPlayer(uint256 index) public view returns (address) {
        return s_players[index];
    }

    function getLastTimeStamp() public view returns (uint256) {
        return s_lastTimeStamp;
    }

    function getInterval() public view returns (uint256) {
        return i_interval;
    }

    function getEntranceFee() public view returns (uint256) {
        return i_entranceFee;
    }

    function getNumberOfPlayers() public view returns (uint256) {
        return s_players.length;
    }
}

```

---

<div class="post-metadata">

**Author:** ![Amxx](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/amxx/32/668_2.png) [@Amxx](https://forum.openzeppelin.com/u/Amxx)\
**Post date:** [June 26, 2024, 8:02am UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/6 "2024-06-26T08:02:53Z")

</div>

Please check our documentation here: [https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable](https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable)

---

<div class="post-metadata">

**Author:** ![Mehdi\_El\_Filahi](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/mehdi_el_filahi/32/21137_2.png) [@Mehdi\_El\_Filahi](https://forum.openzeppelin.com/u/Mehdi_El_Filahi)\
**Post date:** [June 26, 2024, 8:26am UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/7 "2024-06-26T08:26:39Z")

</div>

@Amxx i already tried with this documentation and it is two weeks i m stuck with many errors in the contract and struggled to find example explaining how to create unit tests in javascripts.

---

<div class="post-metadata">

**Author:** ![Amxx](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/amxx/32/668_2.png) [@Amxx](https://forum.openzeppelin.com/u/Amxx)\
**Post date:** [June 27, 2024, 8:49am UTC](https://forum.openzeppelin.com/t/how-to-implement-uups-with-a-solidity-contract-having-vrf-and-automation-features/40913/8 "2024-06-27T08:49:37Z")

</div>

If the documentation is not enough, then I'm not sure what to tell you. At that point you need a tutorial/class more than you need technical support.

The first thing I see is that your ExampleV1 is not usiong the upgradeable contracts

```auto
contract ExampleV1 is ERC20, ERC20FlashMint, VRFConsumerBaseV2Plus, AutomationCompatibleInterface {

```

Which is probably not a goot start.

If you want an example of contracts that went through an upgrade, you can check [the vesting wallets in the forta repository](https://github.com/forta-network/forta-contracts/tree/master/contracts/vesting).

- [v1 of the contract](https://github.com/forta-network/forta-contracts/blob/master/contracts/vesting/VestingWalletV1.sol)
- [v2 of the contract](https://github.com/forta-network/forta-contracts/blob/master/contracts/vesting/VestingWalletV2.sol)
- [the unit tests for the upgrade](https://github.com/forta-network/forta-contracts/blob/master/test/vesting/VestingWallet.upgrade.test.js)
