How does one query the "birth block" of a contract using web3?
2 Answers
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
- 168
- 7
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
- 101
- 2
-
1Do 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