Verify BeaconProxy on Etherscan

Openzeppelin is a great library for developing smart contracts based on the Solidity language, no doubt about that. Its offering of utility, interfaces and contracts to extend is just astonishing and when it comes to smart contract upgradeability it really shines for clarity and simplicity: it took me literally one day to go from not knowing what a proxy contract is to deploying my first beacon proxy.

This post though is not about smart contract development and, while I really wish to thank the guys at Openzeppelin, my intention is to fill a leftover gap, hoping the guys will find a better way and make this post obsolete.

If you have a smart contract using a beacon proxy you are also probably deploying new proxy instances referencing that beacon from a contract, something along the following lines:

    function create(string memory info, uint64 size, uint256 price, uint16 royalties, address allowancesRef) external returns (address) {
        BeaconProxy proxy = new BeaconProxy(
            abi.encodeWithSelector(MintableRewards(address(0x0)).initialize.selector, _msgSender(), info, size, price, royalties, allowancesRef)
        _rewards[_counter.current()] = address(proxy);
        emit CreatedRewards(_counter.current(), msg.sender, size, address(proxy));
        return address(proxy);

The problem arises when you try to get the smart contract resulting from a call to this create function verified on Etherscan: you’ll find this important step quite difficult, but do not worry I’m confident this post will make your day.

Step 1: get the right source code

The address returned by the function above points to the bytecode generated by source code BeaconProxy and to obtain it you can simply run the following (I’m using hardhat, but you can adapt easily to other toolchains):

$> cp -R node_modules/\@openzeppelin/contracts oz
$> npx hardhat flatten oz/proxy/beacon/BeaconProxy.sol > BeaconProxy.src
$> rm -rf oz

Now you need to edit the BeaconProxy.src file and remove all lines containing the SPDX and the pragma solidity directives: if you want to avoid a warning later on you can optionally leave only the first one of each.

At this point you should end up with something like this Gist (please don’t copy it blindly, your version might be different, in which case the procedure doesn’t work).

Step 2: retrieve constructor data

Any data used at construction (and you very likely have data, otherwise why use a beacon proxy?) ends up in your smartcontract bytecode, and that is what Etherscan is going to verify, so you need to retrieve that.

Reconstructing the constructor data manually is possible but very painful, luckily there’s a much easier way to do that: run the Etherscan verification procedure without providing any constructor data.

So go to Etherscan, search for the contract you want to verify, select the Contract tab, and start the verification process.

Start verification process on your proxy beacon contract

Ensure you set the correct compiler version and the contract address match the beacon proxy address created by your create function (or anything equivalent for your situation).

Set beacon proxy parameters

In the screen that comes up clear up the Constructor Arguments field (if populated) and submit a verification request expecting it to fail with a message “Error! Unable to generate Contract ByteCode and ABI”

“Unable to generate bytecode” error

Now you need the address of your beacon, you might have deployed it separately or you might have it created inside your factory contract constructor / initializater function, in your factory smart contract code it is something like:

UpgradeableBeacon _beacon = new UpgradeableBeacon(implementation);

Copy the address of that beacon contract then remove the initial 0x prefix and add 24 leading zeros to pad it to 64 chars (32 bytes), then search for it in the Etherscan section which reports the bytecode it wasn’t able to find.

Search for the beacon address without the 0x prefix and padded to 32 bytes

In my case the address was 0x0f4e07e87a3711629d36143e9eb2793b3125e316 and I searched for 0000000000000000000000000f4e07e87a3711629d36143e9eb2793b3125e316: select anything starting from that address (included) up to the end of the line and you now have your constructor arguments in ABI Encoded format!

Step 3: verify the contract

Now Start Over the verification process, this time you need to select the same values for the Optimization setting and Runs and also providing the sequence you selected earlier as value for the Constructor Arguments field.

Constructor Arguments value set with the bytes sequence from step 2

Now hit the Verify and Publish button and watch the gear spinning until the message you ware striving for pops up!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s