2

I am looking to index all ERC721 and ERC1155 contracts on the blockchain into MongoDB. I do not want to use OpenSea's API and would prefer to fetch all this information directly from the chain.

I've figured out how to detect on a block-by-block basis, which transactions are contract deployments, and by calling the supportsInterface method I can also find out if the contract adheres to the ERC721 or ERC1155 standard.

Is there something I'm missing or would this be the best approach?

const handleError = () => {
    return undefined;
}

const getContractMetadata = async (address) => {
    const abi = [
        'function name() view returns (string name)',
        'function symbol() view returns (string symbol)',
        'function supportsInterface(bytes4 interfaceId) view returns (bool)',
    ];
    const contract = new ethers.Contract(address, abi, provider);
    const [name, symbol, isERC721, isERC1155] = await Promise.all([
        contract.name().catch(handleError),
        contract.symbol().catch(handleError),
        contract.supportsInterface('0x80ac58cd').catch(handleError),
        contract.supportsInterface('0xd9b67a26').catch(handleError),
    ]);
    return { name, symbol, isERC721, isERC1155 };
}

(async() => {
    await mongoClient.connect()
    const db = mongoClient.db('nft')
    const collection = db.collection('collections')

    let blockNumber = 9193266

    while(true) {
        console.log(`Getting block ${blockNumber}'s transactions`)

        let block = await provider.getBlockWithTransactions(blockNumber++)
        let contracts = block.transactions.filter(tx => Boolean(tx.creates))

        if (contracts.length) {
            console.log(`${contracts.length} contract deployments found in ${block.transactions.length} transactions`)

            for (const contract of contracts) {
                let metadata = await getContractMetadata(contract.creates)
                if (metadata.isERC721 || metadata.isERC1155) {
                    let interface = metadata.isERC721 ? 'ERC721' : 'ERC1155'
                    console.log(`Inserting ${interface} contract ${contract.creates} - ${metadata.name} (${metadata.symbol})`)

                    await collection.updateOne({
                        '_id': contract.creates
                    }, { $set: {
                        '_id': contract.creates,
                        creator: contract.from,
                        blockNumber: contract.blockNumber,
                        blockTimestamp: block.timestamp,
                        ...metadata
                    } }, { upsert: true });
                }
            }
        } else {
            console.log(`No contract deployments found in ${block.transactions.length} transactions`)
        }

        let currentBlockNumber = await provider.getBlockNumber()
        if (currentBlockNumber <= blockNumber) {
            break
        }
    }

    await mongoClient.close()
})()
2
  • 1
    There are a few contracts that predates the standars final draft some of them may not be fully compliant. CryptoKitties and CryptoPunks are the most famous.
    – Ismael
    Feb 5, 2022 at 18:04
  • hi @vivekmanglani please follow up, you have an answer here Jul 30, 2022 at 14:16

1 Answer 1

2

Yes, that is exactly the idea. Each created contract. And ERC-165.

The implementation is a little deficient.

I'm not sure where tx.creates is documented. Hmm.

But in general, please note that any transaction is possible to create MULTIPLE contracts. So that approach will not get all of them.

Also note it is possible to deploy a contract in a normal message call (i.e. not a contract deployment) transaction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.