How to verify UUPS proxy on Etherscan

Hi! I'm trying to get UUPS proxy verified on Etherscan, followed

for deployment and attempted to verify using hardhat-etherscan, documented everything in README of a tiny repo with sample code. I also tried uploading code through Etherscan UI with pretty much the same results, which is probably better left for a separate post.

Please help me find that puzzle piece.

:1234: Code to reproduce

:computer: Environment

Hardhat 2.5.0
solc 8.2.0
node v16.3.0
hardhat-ethers 2.0.2
hardhat-etherscan 2.1.4
@openzeppelin/contracts-upgradeable 4.2.0
@openzeppelin/hardhat-upgrades 1.9.0

Are you using the address of the proxy or the implementation for verification?

There is an option on Etherscan to verify a proxy. If you follow the steps, it will tell you that the implementation is not verified and give you the implementation address.

Use that address to verify your contract.

1 Like

Thanks, implementation verification works, same as marking the contract as proxy after the implementation is verified.

The proxy contract itself, unfortunately, stays unverified - similar match is the best I get.

1 Like

You should mark this as resolved. It's a very common topic and it will help users find a solution faster!

But it's not. I was asking specifically about verifying proxy contracts themselves, not implementation. Sorry it's not obvious from the post, I'll update it when I get the access to do so, can't edit the post at the moment.

Hi, welcome! :wave:

I am not sure, but I think the UUPS proxy contract has been verified on the all networks, could you please share the proxy contract address?

1 Like

Ha that's because we don't verify them. OZ team have to verify them. It was fast when I deployed mine, it should be verified soon!

1 Like

@Skyge @madeindreams thanks! That was just a Rinkeby deploy
no need to verify it, obviously. I'll post the actual addresses shortly, I'm about to deploy on Mainnet.

I think the UUPS proxy contract has been verified on the all networks

it's "similar match" on Rinkeby with this version

Is it just a temporary way of doing things, are there plans to automate verification, or is it supposed to be verified once per network because it's not supposed to be changed?

"Similar match" means verified! Note that it says "Contract Source Code Verified". It is supposed to be verified once per network, the proxy contracts do not change.

There are plans to automate verification, but we consider this good enough for now and we have prioritized other work.

If it's not good enough for your use case, do let us know.

2 Likes

Hi @frangio - I'm extending the ERC1967 (it's kind of a hack to make the hardhat-deploy plugin work with UUPS). Do you have any ideas why verification fails for this?

ArtistCreatorProxy.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.7;

import '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol';

contract ArtistCreatorProxy is ERC1967Proxy {
    constructor(
        address _logic,
        address admin_,
        bytes memory _data
    ) payable ERC1967Proxy(_logic, _data) {
        assert(_ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
        _changeAdmin(admin_);
    }

    function getImplementation() external view returns (address implementation) {
        implementation = super._getImplementation();
    }
}

This is how I'm attempting the verification:

  async function verifyContract(address: string, constructorArguments: any[] = []) {
    console.log({ address, constructorArguments });
    let verified = false;
    while (!verified) {
      try {
        //// Verify contract on etherscan
        await run('verify:verify', {
          address,
          constructorArguments,
        });
        verified = true;
      } catch (err) {
        console.log(err);
        if (err.message === 'Contract source code already verified') {
          break;
        } else {
          console.log('\nWaiting 10 seconds...');
          await new Promise((res) => setTimeout(res, 10_000));
        }
      }
    }
  }
};

const artistCreatorProxy = await deployments.deploy('ArtistCreator', {
    from: deployer.address,
    gasLimit: 5000000,
    log: true,
    proxy: {
      owner: deployer.address,
      proxyContract: 'ArtistCreatorProxy',
      execute: {
        methodName: 'initialize',
        args: [],
      },
    },
  });

const creatorImpAddress = (await deployments.get('ArtistCreator_Implementation')).address;

await verifyContract(artistCreatorProxy.address, [creatorImpAddress, deployer.address, '0x']);

Result:

Successfully submitted source code for contract
contracts/ArtistCreatorProxy.sol:ArtistCreatorProxy at 0xe5E3FcF8938b440DF61b344c68A22057Ce367e9c
for verification on Etherscan. Waiting for verification result...

We tried verifying your contract ArtistCreatorProxy without including any unrelated one, but it failed.
Trying again with the full solc input used to compile and deploy it.
This means that unrelated contracts may be displayed on Etherscan...

Successfully submitted source code for contract
contracts/ArtistCreatorProxy.sol:ArtistCreatorProxy at 0xe5E3FcF8938b440DF61b344c68A22057Ce367e9c
for verification on Etherscan. Waiting for verification result...

NomicLabsHardhatPluginError: The contract verification failed.
Reason: Fail - Unable to verify
...
1 Like

@gigamesh I'm not sure why that would be failing. Could be any of the reasons listed in How to verify a contract on Etherscan/BscScan/PolygonScan.

What should work without fail is to deploy the contract and then retrieve from artifacts/build-info the input part of the build info file that contains your contract. This is the Standard JSON Input that you can upload to Etherscan later.

Got it working. Thanks!

It took some time for me to find out how to verify a Rinkeby proxy on Etherscan. It seems like there's no automatic verification. Found this page - https://rinkeby.etherscan.io/proxyContractChecker. Successfully verified my proxy - https://rinkeby.etherscan.io/address/0xDbBc9242F3aa324E0d1A34394d254e73cf0243aE#readContract