11

How does one query the "birth block" of a contract using web3?

will_durant
  • 1,154
  • 1
  • 9
  • 21

2 Answers2

5

One possibility would be, taht the smart contract saves the block number / txid upon the call of the constructor

Otherwise, as stated here How to find contract creation block time with web3?, you will need to search for the creating transaction

0

Use binary search to scan the blockchain, here is the complete code in Golang

package main

import ( "context" "log" "math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"

)

type ContractFinder struct { client *ethclient.Client latestBlock int64 }

func NewContractFinder(provider string) (*ContractFinder, error) { conn, err := ethclient.Dial(provider) if err != nil { return nil, err } latestBlock, err := conn.BlockByNumber(context.Background(), nil) if err != nil { return nil, err }

return &ContractFinder{
    client:      conn,
    latestBlock: latestBlock.Number().Int64(),
}, nil

}

func (c *ContractFinder) codeLen(contractAddr string, blockNumber int64) int { ctx := context.Background() data, err := c.client.CodeAt(ctx, common.HexToAddress(contractAddr), big.NewInt(blockNumber)) if err != nil { log.Fatal("Whoops something went wrong!", err) } return len(data) }

func (c *ContractFinder) GetContractCreationBlock(contractAddr string) int64 { return c.getCreationBlock(contractAddr, 0, c.latestBlock) }

// use binary search to find the block number where the contract was created func (c *ContractFinder) getCreationBlock(contractAddr string, startBlock int64, endBlock int64) int64 { if startBlock == endBlock { return startBlock } // fmt.Println("contractAddr", contractAddr, "startBlock", startBlock, "endBlock", endBlock) midBlock := (startBlock + endBlock) / 2 codeLen := c.codeLen(contractAddr, midBlock) if codeLen > 2 { return c.getCreationBlock(contractAddr, startBlock, midBlock) } else { return c.getCreationBlock(contractAddr, midBlock+1, endBlock) } }

func main() { cttFinder, err := NewContractFinder("https://mainnet.infura.io/v3/[YOURKEY]") if err != nil { log.Fatal("Whoops something went wrong!", err) }

contracts := []string{
    "0x3a4f40631a4f906c2bad353ed06de7a5d3fcb430",
    "0xa4991609c508b6d4fb7156426db0bd49fe298bd8",
}

for _, contract := range contracts {
    creationBlock := cttFinder.GetContractCreationBlock(contract)
    log.Println(contract, creationBlock)
}

}

Remember to replace your provider URL before running.

Here is the complete post about the algorithm

Jerry An
  • 101
  • 2
  • 1
    Do not copy & paste the same answer to multiple questions. Otherwise the system flag them as possible spam. If you have enough reputation flag the questions as duplicates. – Ismael Dec 02 '22 at 05:01