Cannot upgrade contract from address I just transferred admin control to

I saw a few pages that addressed the same error, but the way they got their errors were in a completely different manner as I don’t believe mine stems from the CLI (I am runninf truffle test normally on ganache). I am running tests and deployments locally.
I am attempting to upgrade my contract after transferring admin control to a DAO I made.
When I try this ------->

module.exports = async function (accounts, deployer) {
	let celInstance = await cel.deployed();
	let daoInstance = await dao.deployed();
	newAdmin = daoInstance.address.toString();
	addr = celInstance.address.toString();
	await admin.changeProxyAdmin(addr, newAdmin);
	await upgradeProxy(celInstance.address, version2, {from: newAdmin});

I get the following error -------->
Error: Proxy admin is not the one registered in the network manifest

I deployed proxy for cel in my previous deployment script with

const celInstance = await deployProxy(cel, [Token.address], {deployer, initializer: 'initialize'});

:computer: Environment

Truffle v5.3.8 (core: 5.3.8)
Solidity - 0.5.16 (solc-js)
Node v15.9.0
Web3.js v1.3.6

There’s quite a few of problems here.

A DAO is a smart contract, so you can’t send a transaction from it using JavaScript by specifying its adress in from. You need to call a function of the DAO to ask it to call that other function elsewhere. (Additionally, keep in mind the from parameter in upgradeProxy is ignored.)

In the “Transparent Proxy Pattern” used by default by the Upgrades Plugin, there is a ProxyAdmin contract that is the admin of your proxies, and your deployer account is then the owner of that ProxyAdmin contract. By calling admin.changeProxyAdmin you’re discarding the ProxyAdmin contract from your system. Normally what you want to do is use the admin module in the Upgrades plugin and call admin.transferProxyAdminOwnership to the DAO.

This guide is not exactly what you want to do but may help you understand how to run an upgrade after you’ve transferred ownership to your DAO: Upgrading a contract via a multisig

Looking at your earlier post now, you may already have seen that guide. I realize it doesn’t mention prepareUpgrade, this is the function you need to use instead of upgradeProxy, since you can’t run the upgrade directly it must be via the DAO.

Hi, @frangio. To my understanding, what I’m supposed to do is transfer the proxy admin ownership to the DAO contract via admin.transferProxyAdminOwnership in the migrations. I need to make a prepareUpgrade whenever I want to upgrade. I then need to make a proposal on the DAO that calls for upgradeProxy to a new version. Could you also explain why I get the following output when I call admin.transferProxyAdminOwnership →

✘ 0x51e2f193Bbe74f32Cbc17E8BDdD9c79B5baCA91b (transparent) proxy ownership not affected by admin proxy
✘ 0xeB3F94184634C704bA2894FC2Cc6aE4c0189ECeb (transparent) proxy ownership not affected by admin proxy
✘ 0xB283459B6dB632CeF69019cc5c6727E38f6695B6 (transparent) proxy ownership not affected by admin proxy
✘ 0xC59b8E98C8B3191b4de3A7EC3f68a5F11Bd52De7 (transparent) proxy ownership not affected by admin proxy
:heavy_check_mark: 0xB3BcA413460D45c9A3cc47F77C78baa67Bb555ce (transparent) proxy ownership transfered through admin proxy
:heavy_check_mark: 0xa9894DB732F705F50CE3A194BaD87a4E2C695BdD (transparent) proxy ownership transfered through admin proxy
:heavy_check_mark: 0x757e8Bbbf93d62Ac3EaC428F96b2767C512D8211 (transparent) proxy ownership transfered through admin proxy
:heavy_check_mark: 0xcF307D58fED3ddA294c611CBe4f09d1CC3C2631C (transparent) proxy ownership transfered through admin proxy

To lay it all out, this is what I’m supposed to do:

  1. In migrations, transfer ownership to DAO in migrations.
  2. In tests, prepare upgrade.
  3. propose and execute proposal on DAO to upgrade proxy. (If I am correct, I’m not sure how its possible that I could call upgradeProxy from the DAO).

Thank you so much for your help :slight_smile:


These messages are just making it explicit to you which of the proxies on your network file are affected by the ownership transfer. For some reason, some of your proxies have a different admin and so they are not affected by this operation.

I have one last question. What function should I propose to execute to upgrade on DAO?

The proposal should be to call the upgrade or upgradeAndCall function on the ProxyAdmin instance, with arguments being the proxy address and the implementation address you get from prepareUpgrade.

@frangio I can’t figure out what I’m doing wrong.
I keep getting the error: Error: Returned error: VM Exception while processing transaction: revert Timelock::executeTransaction: Transaction execution reverted. – Reason given: Timelock::executeTransaction: Transaction execution reverted…

debugging the transaction is no help at all.

	let V2 = await prepareUpgrade(celInstance.address, version2);

	let encodedParams = web3.eth.abi.encodeParameters(['address', 'address'], [celInstance.address, V2]);

	await BN(500000)), {from: accounts[2]});

	await govTokenInstance.delegate(accounts[2], {from: accounts[2]});
	await daoInstance.propose([proxyAdmin.address], [0], ['upgrade(address,address)'], [encodedParams], 'upgrade to new version',
	 {from: accounts[2]});

	await helper.advanceBlock();
	await daoInstance.castVote(1, true, {from: accounts[2]});

	for(i=0; i<17280; i++) {
		await helper.advanceBlock();

	await daoInstance.queue(1);
	await helper.advanceTime(172800);
	await daoInstance.execute(1);

This looks good to me and I’m not sure what could be the problem. Can you share a repository where I could reproduce the issue directly?

Can you show the part where you transfer proxy admin ownership to the DAO?

You should try to run some other transaction (not an upgrade) through the DAO to confirm that it’s working.

This has to be a problem with my governance system or I am putting in the parameters for proposal wrong. I tried proposing a proposal that called a function I had tried using before that I know 100% would have worked. this is the repo.

You should add .openzeppelin/unknown-1337.json to .gitignore. This corresponds to the data from your Ganache instances. You’re accumulating proxy addresses from previous runs that don’t get persisted.

Tried to have a look at this but the speed of the test suite makes it very hard to debug. I can’t really help because of that. You should remove the huge loop of advanceBlock calls.

So currently there is no way to mine multiple empty blocks at once so I just drastically shortened the delay to just one block so now testing doesn’t slow down at all anymore. It should be okay to test now. I just pushed this to github. Also, sorry for the confusion, but I was playing around with it and was able to execute a function through a DAO proposal, so it has to be a problem with the upgrades and ownership.

I found the problem and fixed it. First, I was deploying a new instance of the governance, so the addresses were different when I was deploying in the migrations vs tests. Second, the DAO calls an execute function that calls a function in Timelock.sol that actually executes the calldata. With this, the admin ownership had to be transferred to the timelock, not the DAO.

@frangio, Thank you so much for your help!

1 Like