Factory implementation etherscan verification

Here is related question on stack.

I have a contract and its factory. The factory allows cloning of the contract through EIP-1167.

Although I can deploy the factory and verify it easily on etherscan: hardhat verify --network <NETWORK> <FACTORY_ADDRESS>

Validating the factory as a proxy on etherscan requires to verify the implentation. Unfortunately, this doesn't work: hardhat verify --network <NETWORK> <IMPLEMENTATION_ADDRESS>

Successfully submitted source code for contract
contracts/tmp/DummyGreeting.sol:DummyGreeting at 0x8fd5e96cd13e58cd9d90a3f7d7198e3c55892ed2
for verification on the block explorer. Waiting for verification result...

We tried verifying your contract DummyGreeting 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/tmp/DummyGreeting.sol:DummyGreeting at 0x8fd5e96cd13e58cd9d90a3f7d7198e3c55892ed2
for verification on the block explorer. Waiting for verification result...

Error in plugin @nomiclabs/hardhat-etherscan: The contract verification failed.
Reason: Fail - Unable to verify

NomicLabsHardhatPluginError: The contract verification failed.
Reason: Fail - Unable to verify
    at SimpleTaskDefinition.verifySubtask [as action] (/mnt/c/users/julie/workspaces/tmp/node_modules/.pnpm/@nomiclabs+hardhat-etherscan@3.1.0_hardhat@2.10.1/node_modules/@nomiclabs/hardhat-etherscan/src/index.ts:350:9)

The only workaround I found so far is deploying a dummy DummyGreeting aside and verify it. Since it happens to have the same bytecode as the implementation , etherscan will then consider implementation verified. Now with big contracts, you want to avoid the extra costly dummy DummyGreeting deployment.

:1234: Code to reproduce

  • DummyFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "./DummyGreeting.sol";

contract DummyFactory is Ownable {
    event ContractCreated(
        address indexed owner,
        address indexed target,
        string greeting
    );

    address public immutable implementation;

    constructor() {
        implementation = address(new DummyGreeting());
    }

    function make(
        string calldata greeting
    ) external onlyOwner returns (address) {
        address payable clone = payable(Clones.clone(implementation));
        DummyGreeting c = DummyGreeting(clone);
        emit ContractCreated(msg.sender, clone, greeting);
        c.initialize(
            greeting
        );
        return clone;
    }
}
  • DummyGreeting.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import "@openzeppelin/contracts/proxy/utils/Initializable.sol";

contract DummyGreeting is Initializable {
    string public greeting;

    function initialize(
        string memory greeting_
    )
        public
        initializer
    {
        greeting = greeting_;
    }

}

:computer: Environment

hardhat with solc 0.8.15