Deploy ERC20Upgradeable without Proxy for governable upgrades

Basically, I'm trying to deploy an upgradable token implementation without the proxy. I have a proxy deployed already, and I would like to update the implementation using governance. I've created an UUPS upgrade able token (minified for the example)

    contract GovernanceToken is Initializable, ERC20Upgradeable, ERC20PermitUpgradeable, ERC20VotesUpgradeable, OwnableUpgradeable, UUPSUpgradeable {
        /// @custom:oz-upgrades-unsafe-allow constructor
        constructor() {
        function initialize() initializer public {
            __ERC20_init("GovernanceToken", "GT");

My deploy script looks like this:

    const deployGovernanceToken: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
      // @ts-ignore
      const { getNamedAccounts, deployments, network } = hre
      const { deploy, save, log, get } = deployments
      const { deployer } = await getNamedAccounts()

      const governanceTokenContractFactory = await ethers.getContractFactory(GOVERNANCE_TOKEN_NAME);
      const deployedProxy = await upgrades.deployProxy(governanceTokenContractFactory, [], {
        initializer: "initialize",
        kind: "uups",

      await deployedProxy.deployed();
      const governanceToken = await governanceTokenContractFactory.attach(

      const timeLock = await get(TIMELOCK_CONTROLLER_NAME)
      const governanceTokenContract = await ethers.getContractAt(GOVERNANCE_TOKEN_NAME, governanceToken.address)

      const transferTx = await governanceTokenContract.transferOwnership(timeLock.address)
      await transferTx.wait(1)

I would like to upgrade my token, however it's owned by the timelock so I cannot upgrade it from hardhat, so I'd like to deploy another version of the token so I can upgrade it though governance.

This is my upgrade script:

    const { getNamedAccounts, deployments, network } = hre
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const timelockAddress = '0x...'
    const governanceTokenV2 = await ethers.getContractFactory(GOVERNANCE_TOKEN_NAME);
    const governanceTokenContract = await governanceTokenV2.deploy();
    log(`Upgraded Token at ${governanceTokenContract.address}`)


    const owner = await governanceTokenContract.owner();
    log(`Verified Token at ${governanceTokenContract.address}`)
    log(`owner: ${owner}`)

When I run this I get an error:

Deploying governanceToken and waiting for confirmations...
Upgraded Token at 0x5Fb...
owner: 0x0000000000000000000000000000000000000000

Error HH604: Error running JSON-RPC server: ERROR processing C:..\deploy\00-deploy-upgraded-Token.ts:
Error: VM Exception while processing transaction: reverted with reason string 'Ownable: caller is not the owner'

The token I'm deploying claims the owner is the ZERO_ADDRESS, perhaps this is because the storage is usually associated with the proxy?

How can I deploy this token and transfer ownership to the proxy?

**Note: ** I've also tried calling initialize directly after deployment and I get an error:

reason="execution reverted: Initializable: contract is already initialized"

Hi, welcome to the community! :wave:

I think you should call initialize() to claim the ownership.

When I call initialize it claims it's already been initialized

It seems like you deployed your token in deploy script, so have you passed the right contract address in upgrade script?