ERC20 generated by wizard with Burnable, Permit, Votes, Ownable and UUPS does not seem deployable

I've generated the a contract using the wizard, and I am trying to test it and getting the following error:

     Error: Contract `contracts/TokenV1.sol:TokenV1` is not upgrade safe

@openzeppelin/contracts-upgradeable/governance/utils/VotesUpgradeable.sol:261: Variable `op` is an internal function
    Use external functions or avoid functions in storage.
     If you must use internal functions, skip this check with the `unsafeAllow.internal-function-storage`
     flag and ensure you always reassign internal functions in storage during upgrades
    https://zpl.in/upgrades/error-009

:1234: Code to reproduce

// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract TokenV1 is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PermitUpgradeable, ERC20VotesUpgradeable, OwnableUpgradeable, UUPSUpgradeable {
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address initialOwner) initializer public {
        __ERC20_init("xxx", "xxx");
        __ERC20Burnable_init();
        __ERC20Permit_init("xxx");
        __ERC20Votes_init();
        __Ownable_init(initialOwner);
        __UUPSUpgradeable_init();

        _mint(msg.sender, 2222 * 10 ** decimals());
    }

    function _authorizeUpgrade(address newImplementation)
        internal
        onlyOwner
        override
    {}

    // The following functions are overrides required by Solidity.

    function _update(address from, address to, uint256 value)
        internal
        override(ERC20Upgradeable, ERC20VotesUpgradeable)
    {
        super._update(from, to, value);
    }

    function nonces(address owner)
        public
        view
        override(ERC20PermitUpgradeable, NoncesUpgradeable)
        returns (uint256)
    {
        return super.nonces(owner);
    }
}

and the test code:

import {
    time,
    loadFixture,
} from "@nomicfoundation/hardhat-toolbox-viem/network-helpers";
import { expect } from "chai";
import hre from "hardhat";
import { getAddress, parseGwei } from "viem";

describe("TokenV1", function () {
    // and reset Hardhat Network to that snapshot in every test.
    async function deployFixture() {
        const decimals = 18;
        const TokenV1 = await hre.ethers.getContractFactory("TokenV1");


        // Contracts are deployed using the first signer/account by default
        const [owner, otherAccount] = await hre.viem.getWalletClients();

        const token = await hre.upgrades.deployProxy(TokenV1, []);



        const publicClient = await hre.viem.getPublicClient();

        return {
            decimals,
            token,
            owner,
            otherAccount,
            publicClient,
        };
    }

    describe("Deployment", function () {
        it("Should return the right decimals", async function () {
            const { token, decimals } = await loadFixture(deployFixture);

            expect(await token.decimals()).to.equal(decimals);
        });
    });
});

:computer: Environment

See https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/1037#issuecomment-2176681177 for details and workaround.

2 Likes

This is fixed in @openzeppelin/upgrades-core@1.34.1, you can update your dependencies to use that package which is a transitive dependency of the Hardhat Upgrades plugin.

For example: npm install @openzeppelin/upgrades-core@latest

Very nice, thank you! I'll go try that out. Appreciate the quick turnaround!