sourcify icon indicating copy to clipboard operation
sourcify copied to clipboard

Verification Failed: no_match - Ethereum Mainnet ERC5202 Contract

Open Argeric opened this issue 5 months ago • 5 comments

Verification Job Failed

Job ID: 8a141550-41c3-4d9f-82ca-b387b8092531 Chain: Ethereum Mainnet (1) Contract Address: 0xf6134998c7a4e4ADDf71E2Ca1273A480E1d12d5d Error Code: no_match Server URL: https://sourcify.dev/server

Error Details

The deployed and recompiled bytecode don't match.

Additional Information

  • Job Started: 2025-07-28T09:53:26.000Z
  • Job Finished: 2025-07-28T09:53:42.000Z

User Input and Expectation

Why do you expect this verification to succeed? The contract has been verified on ethereum scan on mainnet. This is an ERC-5202 Blueprint contract.

Files Used: https://etherscan.io/address/0xf6134998c7a4e4addf71e2ca1273a480e1d12d5d#code#L1

Argeric avatar Jul 28 '25 10:07 Argeric

Just took a look. This is a Vyper contract and an instance of #2233

kuzdogan avatar Jul 29 '25 08:07 kuzdogan

This doesn't appear to be an instance of #2233. It's not fixed by the latest release of the verification ui

marcocastignoli avatar Aug 26 '25 09:08 marcocastignoli

This is a ERC-5202 (Blueprint) contract as pointed out, and such contracts do not fit into the standard verification process of comparing onchain vs recompiled bytecodes. From my understanding the Blueprint pattern is how Vyper handles factories. The bytecode here is structured and we need to take into account the data and metadata snippets. Blockscout has a module handling Blueprints for reference.

Vyper also has a built-in create_from_blueprint function to create children contracts: https://docs.vyperlang.org/en/stable/built-in-functions.html#create_from_blueprint

I'll have a more detailed look tomorrow with a fresh mind

kuzdogan avatar Sep 10 '25 14:09 kuzdogan

Now I see the situation. To summarize the ERC-5202 lays out an EVM bytecode spec (not a language spec) to deploy factories onchain that are not meant to be interacted with but only to be EXTCODECOPY'ed to save gas for repetetive deployments.

For example, if you deploy a contract with this pattern, you can use the following Vyper snippet to deploy new children contracts:

def deploy_new(name: String[32], symbol: String[32], supply: uint256, blueprint: address) -> address:
    # code_offset default is 3, to skip ERC-5202 preamble
    new_addr: address = create_from_blueprint(blueprint, name, symbol, supply)
    return new_addr

To get the deployment bytecode for blueprint you can use vyper -f blueprint_bytecode

With that, this does not really fit into a standard verification process of comparing onchain vs recompiled bytecodes. Because the onchain code will have prefixes before the recompiled codes of the contract that is "being blueprinted".

For this example above, with their verified source code on Etherscan and Vyper:

  • compiled runtime: <COMPILED_RUNTIME>
  • compiled creation: <constructor_code> <COMPILED_RUNTIME> <cbor_auxdata> = `<COMPILED_CREATION>
  • onchain runtime: 0xfe7100 <COMPILED_CREATION>
    • Here runtime code has "compiled creation" because the onchain runtime code is basically the initcode that deploys this contract.
    • 00 means in binary: 00000000 = 00 (version) + 000000 (data length)` so this contract has no data added.
  • onchain creation: 0x615ddf3d81600a3d39f3 fe7100 <COMPILED_CREATION>
    • This is the bytecode snippet to deploys the blueprint as laid out in the spec deploy_bytecode = b"\x61" + len_bytes + b"\x3d\x81\x60\x0a\x3d\x39\xf3" and can be seen in the Blockscout code.

Considering this, again the given source code actually does not produce the onchain bytecode. However the children contracts copying code from this blueprint will actually match the source code.

So to me it seems we can't and maybe should not verify this contract. There's still benefit to verify it as an ERC5202 contract like Etherscan and Blockscout does:

https://etherscan.io/address/0xf6134998c7a4e4addf71e2ca1273a480e1d12d5d#code#L1 https://eth.blockscout.com/address/0xf6134998c7a4e4addf71e2ca1273a480e1d12d5d?tab=contract

For that we need to somehow mark this special case in the database and this seems very complicated to me. Another possibility is to do this on the server's end or on the frontend where, for a contract requested, we first parse the leading 2 bytes to see if it's 0xfe71xxxx and then we can confidently say this is a blueprint bytecode. After that, however, we need to find a matching bytecode for the <COMPILED_CREATION> but we don't do this yet. This will be done with #1642

I think this resembles our discussion on Minimal Proxies #1624. There also there was no source code corresponding to the bytecode. Here we have at least some source code whose bytecode is prefixed with some spec'ed code. I feel resolving this also on the fly is the way to go. But then again the question is should we somehow mark these special cases in the database. Maybe this also shows the need for a special case table in the database.

Let me know what your thoughts are on this.

kuzdogan avatar Sep 11 '25 09:09 kuzdogan

Btw thanks for reporting this @Argeric

Are you aware of any contracts deployed via this blueprint? Since deployed contracts just copy the bytecode and don't call this blueprint, it's not possible to see those contracts on block explorers.

kuzdogan avatar Sep 11 '25 09:09 kuzdogan