How to get Smart Contract Creation Block Number with NodeJS

Lets say you have an application that needs to index Smart Contract events. To index past events, you have to first know what blocks you should be looking at. It does not need to be explained, that you should be looking at blocks that were created after the contract was deployed. So you need to know what was the block number when contract was created. If you deployed it, then you probably know it or you can look it up on Etherscan. But, we are here to automate things.

So, how to get Smart Contract Creation Block Number programmatically?

First thing that we can ask ourselves is: If we can’t get creation block number directly, what can we get?

Well, we can get the code that is deployed to an address at any block, and we know that before the Smart Contract was deployed, the address had no code. The first block where there is code at the address, is the block when contract was created. Therefore, we can search for two consecutive blocks: one where address has no code and one where it does.

But wouldn’t that take forever? Yes, if we were going to look at every block ever created. But, we don’t have to. We can use a search algorithm like Binary Search. If you are not familiar with how the algorithm works, I recommend checking out this explanation.

Implementation

We will be implementing the solution in Node with Ethers. So, let’s assume you have your Node app set up.

First import ethers and connect to your RPC provider.

import { ethers } from "ethers";

const contract_address = process.env.CONTRACT_ADDRESS;
const provider = new ethers.providers.InfuraProvider("mainnet",process.env.INFURA_KEY);


Now lets look at how we can check if code is deployed at an address.

If we look at Ethers docs, we can find provider.getCode( address [ , blockTag = latest ] ) method. The method returns contract code of an address at a specified block. If there is no code, it returns 0x string. So given this, we can check the length of the string and determine if there is code deployed or not.

const code = await provider.getCode(<CONTRACT_ADDRESS>, <BLOCK_NUMBER>);

if(code.length > 2) {
  console.log("CONTRACT DEPLOYED");
} else {
  console.log("CONTRACT NOT DEPLOYED");
}

Let’s use this together with Binary Search algorithm and create a function to get the contract creation block number.

const getCreationBlock = async (provider, contract_address, start_block, end_block) => {
    if(start_block === end_block) return start_block;

    const mid_block = Math.floor((start_block + end_block) / 2);
    const code = await provider.getCode(contract_address, mid_block);

    if(code.length > 2) {
        return await getCreationBlock(provider, contract_address, start_block, mid_block);
    } else {
        return await getCreationBlock(provider, contract_address, mid_block+1, end_block);
    }
}

You can see that we need start_block and end_block to execute getCreationBlock(). start_block can be set to 0, but for end_block we will need to find the latest block number. We can do that by calling provider.getBlockNumber().

const current_block = await provider.getBlockNumber();

Now all we need is to call getCreationBlock().

const creation_block = await getCreationBlock(provider, contract_address, 0, current_block);

You can check an example app that uses the above code here.