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(
address(beacon),
abi.encodeWithSelector(MintableRewards(address(0x0)).initialize.selector, _msgSender(), info, size, price, royalties, allowancesRef)
);
_counter.increment();
_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.

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).

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”

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.

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.

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