Cannot transfer ownership of UUPSUpgradeable Contract to Gnosis Safe

I’m unable to transfer ownership of a UUPSUpgradeable + OwnableUpgradeable to a Gnosis Safe per the tutorial here: OpenZeppelin Upgrades: Step by Step Tutorial for Hardhat by @abcoathup

:computer: Environment

"@openzeppelin/contracts": "^4.0.0",
"@openzeppelin/contracts-upgradeable": "^4.1.0",
"solc": "0.8.2",
"hardhat": "^2.0.8",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^2.1.2",
"@nomiclabs/hardhat-waffle": "^2.0.0",
"@opengsn/gsn": "^2.1.0",
"@openzeppelin/hardhat-upgrades": "^1.6.0",
"chai": "^4.2.0",
"ethereum-waffle": "^3.0.0",
"ethers": "^5.0.0",
"hardhat": "^2.0.8",


What’s the recommended way to transfer ownership of of a UUPSUpgradeable Contract to a Gnosis Safe? The goal is to use Defender + Gnosis to upgrade this. The contract in question inherits from: Initializable, ERC2771ContextUpgradeable, UUPSUpgradeable, OwnableUpgradeable

:1234: Code to reproduce

When this code is run:

import { upgrades } from "hardhat";

const GNOSIS_SAFE = '0x9E2028cd1Fb68b908cF49F4743f2E52d3c0A7e9b';

async function main () {
  console.log('Transferring ownership of ProxyAdmin...');
  await upgrades.admin.transferProxyAdminOwnership(GNOSIS_SAFE);
   console.log('Transferred ownership of ProxyAdmin to:', GNOSIS_SAFE);

  .then(() => process.exit(0))
  .catch(error => {

Fails with error:

Transferring ownership of ProxyAdmin...
Error: No ProxyAdmin was found in the network manifest
    at getManifestAdmin (.../node_modules/@openzeppelin/hardhat-upgrades/src/admin.ts:57:11)
    at Object.transferProxyAdminOwnership (...node_modules/@openzeppelin/hardhat-upgrades/src/admin.ts:29:19)
    at main (.../scripts/transfer-ownership.ts:7:3)

This makes sense because there is no admin entry in the rinkeby.json config. If there was one, we would get the warning:

Warning: A proxy admin was previously deployed on this network

    This is not natively used with the current kind of proxy ('uups').
    Changes to the admin will have no effect on this new proxy.

For context, the script was deployed with:

import { ethers, upgrades } from "hardhat";

async function main() {
  const RINKEBY_TRUSTED_FORWARDER = '0x956868751Cc565507B3B58E53a6f9f41B56bed74'  
  const MyContractFactory = await ethers.getContractFactory("MyContract");
  const myContract = await upgrades.deployProxy(MyContractFactory, [RINKEBY_TRUSTED_FORWARDER], {kind: 'uups'});
  console.log("Deployed to:", myContract.address);

  .then(() => process.exit(0))
  .catch(error => {

So what’s the recommended way to do the upgrade, while preserving the right configuration settings here for future upgrades?

Hi, so do you follow the tutorial step by step?
I can not find the pacakge in your package.json : @openzeppelin/hardhat-upgrades, so did you install it by npm install --save-dev @openzeppelin/hardhat-upgrades

Yes, I do have hardhat-upgrades installed, updated the post to reflect the dev dependecies that are installed.

So have you also deployed the contracts with the

await upgrades.deployProxy(Your_Contract_Factory)
1 Like

Yes I did.

It generated the rinkeby.json file and the contract exists. However the rinkeby.json file does not have an “admin” item because uups does not require or use an admin.

But it appears that the call to transferProxyAdminOwnership requires an admin entry.

Hi @varunsrin. The problem is that UUPS contracts do not have a ProxyAdmin, so the tutorial doesn’t apply in the same way. Sorry about the confusion with that, we have to add a comment about this.

With UUPS proxies as deployed by the plugins, the proxy owner will be the account that deployed the contract. So if you want to transfer ownership you should take an instance of your contract and call the transferOwnership function directly.