Skip to content

Repository files navigation

blockscout-go-api

Go Reference

Golang client for Blockscout explorers.

  • REST API v2 with typed requests/responses and context.Context
  • Typed query params for filters, search, pagination, advanced filters, and account abstraction
  • Zero runtime dependencies; transport uses the Go standard library
  • Legacy Etherscan-compatible API surface with context-aware variants
  • ETH RPC helper methods

While there are several explorers available to blockchain projects, most are closed systems (ie Etherscan, Etherchain). Blockscout provides a much needed open-source alternative.

Usage

go get github.com/PositiveSecurity/blockscout-go-api

Supported Go version: Go 1.22 or newer.

Versions after v0.1.0 contain source-incompatible API corrections and are not backwards compatible with v0.1.0.

Create a REST API v2 client:

package main

import (
	"context"
	"fmt"
	"log"

	blockscout "github.com/PositiveSecurity/blockscout-go-api"
	"github.com/PositiveSecurity/blockscout-go-api/client"
)

func main() {
	api := blockscout.New(blockscout.EthMainnetBase)

	addr, err := api.GetAddress(context.Background(), "0xd8da6bf26964af9d7eed9e03e53415d37aa96045")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(addr.CoinBalance)

	params := &client.ListAddressTransactionsParams{
		Filter: "from",
	}
	txs, err := api.ListAddressTransactions(context.Background(), addr.Hash, params)
	if err != nil {
		log.Fatal(err)
	}
	if txs.HasNextPage() {
		if err := txs.ApplyNextPage(params); err != nil {
			log.Fatal(err)
		}
	}
}

Use blockscout.New as the main public entry point. The client package remains available for request/response types such as client.ListTransactionsParams.

Token naming note: legacy Etherscan-compatible GetToken is kept for backwards compatibility and returns common.TokenInfo. Use GetTokenV2 for REST API v2 token details.

Typed filters and pagination can be reused without hand-building query strings:

itemsCount := 10
params := &client.ListTransactionsParams{
	Filter:     "validated",
	ItemsCount: &itemsCount,
}

page, err := api.ListTransactions(ctx, params)
if err != nil {
	log.Fatal(err)
}
if page.HasNextPage() {
	if err := page.ApplyNextPage(params); err != nil {
		log.Fatal(err)
	}
	nextPage, err := api.ListTransactions(ctx, params)
	if err != nil {
		log.Fatal(err)
	}
	_ = nextPage
}

For inspection-heavy shapes, typed and raw helpers can be used side by side:

contract, err := api.GetSmartContract(ctx, "0x...")
rawContract, err := api.GetSmartContractRaw(ctx, "0x...")
abi, err := api.GetSmartContractABIEntries(ctx, "0x...")
rawABI, err := api.GetSmartContractABIRaw(ctx, "0x...")

_, _, _, _ = contract, rawContract, abi, rawABI

Smart-contract verification:

resp, err := api.VerifySmartContractViaFlattenedCode(ctx, "0x...", client.VerifyFlattenedCodeRequest{
	CompilerVersion: "v0.8.17+commit.8df45f5f",
	LicenseType:     client.LicenseMIT,
	SourceCode:      "pragma solidity ^0.8.17; contract Token {}",
	ContractName:    "Token",
})

REST API v2 coverage

  • Addresses, transactions, blocks, tokens, smart contracts, verification, stats, and search
  • Pagination helpers via PaginatedResponse[T], HasNextPage, NextQuery, and ApplyNextPage
  • Raw helpers for smart-contract JSON/ABI plus parsed ABI entries
  • CSV downloads for supported address, token-holder, advanced-filter, and Celo reward endpoints
  • Backend/config, withdrawals, advanced filters, account abstraction, and main-page endpoints
  • Watchlist transactions, NFT metadata refetch helpers, and unified v1 search
  • Chain-specific endpoints for Beacon deposits, Arbitrum, Optimism, Scroll, Celo, MUD, Polygon zkEVM, ZKsync, Zilliqa, and execution-node transactions

KnownExplorers is intentionally small: 20 popular mainnet Blockscout-compatible explorers with chain ID, name, base URL, and derived API URLs. Pass any other Blockscout-compatible URL directly to blockscout.New(baseURL).

Timeouts, retries, and rate limits

  • The client does not retry requests automatically and does not apply built-in rate-limit backoff.
  • Use context.Context, client.WithTimeout, or a custom http.Client/RoundTripper to enforce request deadlines and retry policy.
  • WithTimeout clones the configured http.Client before setting Timeout, so a caller-provided client is not mutated.
  • Blockscout rate limits and 429 behavior can vary by hosted instance; callers should handle 429/5xx responses according to the target explorer's policy.

Concurrency

  • A configured client can be used concurrently for requests.
  • Configure the client before concurrent use; do not mutate URL, URLv2, or call URL setter methods while requests are in flight.

Testing

make check

Without make, run the local checks directly:

gofmt -l .
go vet ./...
go run honnef.co/go/tools/cmd/staticcheck@v0.7.0 ./...
go test ./...

On Windows without make, the same local gate is available as:

.\scripts\check.ps1

Run the live e2e runner:

make e2e

The default test suite is local and does not require a live explorer. Optional live smoke tests are gated behind BLOCKSCOUT_LIVE_TESTS=1; the broader cmd/blockscout-e2e runner can probe a real Blockscout instance and write a pass/fail/skip report with sampled response shapes. See cmd/blockscout-e2e/README.md for all runner flags and release-readiness profiles.

Legacy API

The old API is still available:

package main

import (
	"fmt"
	"log"

	"github.com/PositiveSecurity/blockscout-go-api"
	"github.com/PositiveSecurity/blockscout-go-api/client"
	"github.com/PositiveSecurity/blockscout-go-api/common"
)

func main() {

	var api client.BlockScoutAPIClient

	// set your url api
	api.SetBlockScoutApiUrl(blockscout.EthMainnet)
	api.SetBlockScoutApiUrlV2(blockscout.EthMainnetV2)

	// get the current block number
	block, err := api.GetCurrentBlockRpcApi()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(block)

	// convert *big.Int to uint64
	blocknum, err := common.BigIntToUint64(block)
	if err != nil {
		log.Fatal(err)
	}

	// get the ETH balance  of vitalik.eth on the current block number
	addr := "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
	balance, err := api.GetEthBalance(addr, blocknum)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(balance)

	// get the latest indexed account balance via the legacy balance action
	latestBalance, err := api.GetAccountBalance(addr)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(latestBalance)

	// api v2
	body, err := api.GetBlockInfo("0")
	if err != nil {
		log.Fatal(err)
	}

	pretty, err := common.PrettyJSON(body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(pretty)

}

Releases

Used by

Contributors

Languages