How to solve OpenSea's "We couldn’t find this contract." error for ERC721 Validation
Published: 2022-03-01 16:22:15

You may have a perfectly valid ERC721 contract yet OpenSea gives you an error when you try to add your ERC721 contract to OpenSea.

This is the URL for adding an ERC721 collection to OpenSea's testnet which uses Rinkeby: https://testnets.opensea.io/get-listed/step-two

This is the error you can get:

> We couldn't find this contract. Please ensure that this is a valid ERC721 or ERC1155 contract deployed on Rinkeby and that you have already minted items on the contract.

You may get this error even if your contract is compliant with the ERC721 standard. A team from the [Opinyour project](https://www.opinyour.com/) and myself  [debugged](https://dev.to/mudgen/how-to-debug-code-2850) OpenSea's ERC721 validation and discovered what we think is the problem and a solution that works.

## How OpenSea ERC721 Validation Works

From behavior of OpenSea's ERC721 validation we discovered how OpenSea validates contracts as ERC721 or not. This investigation and discovery occurred on the Rinkeby network. Based on observed behavior this is how OpenSea ERC721 validation works:

1. OpenSea automatically monitors all new contracts that are deployed. The moment OpenSea detects a new contract has been deployed it calls `contract.supportsInterface(type(IERC721).interfaceId)` on that contract. If the function call returns true then OpenSea adds it to its list or database of potential ERC721 contracts. If the function call returns false then OpenSea will not detect it as an ERC721 contract and any attempts at validation fails.

2. OpenSea checks during deployment and after deployment (for any contract that passes step 1 above) if any ERC721 Transfer events have been emitted from a contract. If not then any validation fails.

If a contract passes step 1 and 2 then it will pass ERC721 validation on OpenSea's [validation webpage](https://testnets.opensea.io/get-listed/step-two).

## When OpenSea ERC721 Validation Fails

For a lot of contracts OpenSea's current ERC721 validation strategy works. But there are two cases that I know where OpenSea will fail to validate smart contracts that comply fully with the ERC721 standard. Here are the two cases:

1. If OpenSea's infrastructure that processes newly deployed contracts on a blockchain stops working or develops a backlog then newly deployed ERC721 contracts will fail validation until OpenSea's monitoring infrastructure is working again or until the backlog of unprocessed contracts is handled.

2. A proxy contract that is upgraded after deployment to support ERC721 can fail validation. The reason is because OpenSea validates contracts when they are deployed, but such contracts don't implement ERC721 until after they are deployed. See solutions to this below.

Here is an example of a scenario where ERC721 validation fails and how to get it working:

1. We deploy an [EIP2535 diamond](https://eips.ethereum.org/EIPS/eip-2535).
2. Right after deployment we upgrade the diamond to fully implement the ERC721 standard.

> *Note: Introduction article to EIP2535 Diamonds here: https://eip2535diamonds.substack.com/p/introduction-to-the-diamond-standard*

As mentioned before such a diamond contract can fail OpenSea ERC721 validation if OpenSea validates the diamond before the upgrade transaction adds the ERC721 functions. Also understand that it is possible for ERC721 validation to pass in this case if OpenSea has a blacklog of contracts to process and by the time it processes our diamond the upgrade transaction has been added to the blockchain.

The very specific solution to this is to add the `supportsInterface(bytes4 _interfaceId)` function to the diamond when it is deployed. This is easily done by adding the function to the diamond in the constructor function of the diamond. It could also be added directly to the diamond as an [immutable function](https://eips.ethereum.org/EIPS/eip-2535#terms). Also be sure that the function returns `true` for the `type(IERC721).interfaceId` argument.

Here is a link to code that shows an example of adding the `supportsInterface` function to a diamond in its constructor function: https://gist.github.com/mudgen/fe2ee945446e64c56c9c11c1796c1f3b

Because we now understand why validation fails and generally how to fix it (add supportsInterface function during deployment), there are a number of different ways to implement a solution. 

One solution is to add all the ERC721 functions to the diamond during deployment. It is possible to add the ERC721 functions to the diamond in the diamond's proxy constructor function.