I have an ERC20 upgradeable contract (see MyToken.sol
below) that I am deploying to Rinkeby (using 2_deploy_token.js
and 3_transfer_ownership.js
for migration files). I'm trying to transfer the proxy contract ownership to my Gnosis Safe so that only it can upgrade the contract next time. However, I get an error:
Error: No ProxyAdmin was found in the network manifest
How do I address this error?
I haven't seen any post addressing this exact error, only Error: Proxy admin is not the one registered in the network manifest
(like this post), which is different.
Code to reproduce
MyToken.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.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 MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() initializer {}
function initialize(string memory _name, string memory _symbol) initializer public {
__ERC20_init(_name, _symbol);
__ERC20Burnable_init();
__Pausable_init();
__Ownable_init();
__UUPSUpgradeable_init();
}
// other functions
}
2_deploy_token.js
:
const { deployProxy } = require('@openzeppelin/truffle-upgrades');
const MyToken = artifacts.require('MyToken.sol');
module.exports = async function (deployer) {
const name = 'MyToken';
const symbol = 'MTN';
const instance = await deployProxy(
MyToken,
[name, symbol],
{ deployer }
);
};
3_transfer_ownership.js
:
const { admin } = require('@openzeppelin/truffle-upgrades');
module.exports = async function (deployer, network) {
// Use address of your Gnosis Safe
const gnosisSafe = 'GNOSIS_SAFE';
// The owner of the ProxyAdmin can upgrade our contracts
await admin.transferProxyAdminOwnership(gnosisSafe);
console.log('Ownership transferred to', gnosisSafe);
}
};
truffle-config.js network
:
rinkeby: {
networkCheckTimeout: 1000000, // 10000,
provider: () => new HDWalletProvider({
mnemonic: {
phrase: process.env.MNEMONIC
},
providerOrUrl: `wss://rinkeby.infura.io/ws/v3/${process.env.INFURA_PROJECT_ID}`
}),
network_id: 4, // Rinkeby's id
gas: 4500000, // Rinkeby has a lower block limit than mainnet
timeoutBlocks: 300, // # of blocks before a deployment times out (minimum/default: 50)
skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
}
Environment
- Truffle ^5.4.29
- Node v16.13.1
- npm v8.1.2