Skip to main content
Package ethclient wraps the low-level rpc.Client and exposes every standard eth_* method as a typed Go function. It is the recommended starting point for any Go application that needs to talk to an Ethereum node.
import "github.com/ethereum/go-ethereum/ethclient"

Connecting

client, err := ethclient.Dial("https://mainnet.infura.io/v3/<key>")
if err != nil {
    log.Fatal(err)
}
defer client.Close()
Both Dial and DialContext return (*Client, error):
func Dial(rawurl string) (*Client, error)
func DialContext(ctx context.Context, rawurl string) (*Client, error)
Subscriptions (SubscribeNewHead, SubscribeFilterLogs) require a persistent connection. Use WebSocket or IPC — HTTP connections do not support server-push notifications.

Method reference

Blockchain

// Current chain ID (replay-protection identifier)
func (ec *Client) ChainID(ctx context.Context) (*big.Int, error)

// Most recent block number
func (ec *Client) BlockNumber(ctx context.Context) (uint64, error)

// Full block by number; pass nil for the latest block
func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error)

// Full block by hash
func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)

// Block header only (cheaper — one RPC round-trip instead of two)
func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)

// All receipts for a block
func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.Receipt, error)

// Current sync progress; returns nil if the node is fully synced
func (ec *Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error)
BlockByNumber and BlockByHash require two RPC calls: one for the header and one for uncles. Use HeaderByNumber when you do not need transaction data.
Special block number tags — pass a negative *big.Int corresponding to rpc.BlockNumber constants:
ConstantMeaning
nillatest
rpc.LatestBlockNumberlatest
rpc.SafeBlockNumbersafe head
rpc.FinalizedBlockNumberfinalized
rpc.PendingBlockNumberpending
rpc.EarliestBlockNumbergenesis

Transactions

// Fetch a transaction; isPending is true if not yet mined
func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error)

// Receipt for a mined transaction (returns ethereum.NotFound for pending)
func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)

// Inject a signed transaction into the pending pool
func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error

// Number of transactions in a block
func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error)

State

// Wei balance at a given block (nil = latest)
func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)

// Raw storage slot value
func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error)

// Contract bytecode
func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)

// Account nonce (use PendingNonceAt for the next available nonce)
func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error)
func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)

Contract calls and gas

// Execute a read-only call against the EVM (eth_call)
func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)

// Estimate gas needed for a transaction
func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error)

// Legacy gas price oracle
func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error)

// EIP-1559 priority fee suggestion
func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error)

// EIP-4844 blob base fee
func (ec *Client) BlobBaseFee(ctx context.Context) (*big.Int, error)

// Fee history for the last N blocks
func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error)

Logs

// One-off log query
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error)

// Streaming log subscription (WebSocket / IPC only)
func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
ethereum.FilterQuery fields:
type FilterQuery struct {
    BlockHash *common.Hash     // pin to a single block, or...
    FromBlock *big.Int         // ...use a range (nil = genesis)
    ToBlock   *big.Int         // nil = latest
    Addresses []common.Address // restrict to these contracts
    Topics    [][]common.Hash  // topic filter matrix
}

Subscriptions

// Receive new block headers as they arrive (WebSocket / IPC only)
func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error)
Subscriptions implement ethereum.Subscription:
type Subscription interface {
    Unsubscribe()
    Err() <-chan error
}

Full example

package main

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

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://mainnet.infura.io/v3/<key>")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    ctx := context.Background()

    // Latest block number
    blockNum, err := client.BlockNumber(ctx)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("block:", blockNum)

    // Full block
    block, err := client.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("txs in block: %d\n", len(block.Transactions()))

    // Balance of an address
    addr := common.HexToAddress("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
    balance, err := client.BalanceAt(ctx, addr, nil) // nil = latest
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("balance (wei):", balance)

    // Build and send an EIP-1559 transfer
    privateKey, err := crypto.HexToECDSA("<hex-private-key>")
    if err != nil {
        log.Fatal(err)
    }
    chainID, _ := client.ChainID(ctx)
    nonce, _ := client.PendingNonceAt(ctx, crypto.PubkeyToAddress(privateKey.PublicKey))
    tip, _ := client.SuggestGasTipCap(ctx)

    tx := types.NewTx(&types.DynamicFeeTx{
        ChainID:   chainID,
        Nonce:     nonce,
        GasTipCap: tip,
        GasFeeCap: new(big.Int).Add(tip, big.NewInt(2e9)), // tip + 2 gwei headroom
        Gas:       21000,
        To:        &addr,
        Value:     big.NewInt(1e18), // 1 ETH in wei
    })

    signer := types.LatestSignerForChainID(chainID)
    signedTx, err := types.SignTx(tx, signer, privateKey)
    if err != nil {
        log.Fatal(err)
    }

    if err := client.SendTransaction(ctx, signedTx); err != nil {
        log.Fatal(err)
    }
    fmt.Println("sent:", signedTx.Hash())
}

Simulated backend for tests

The ethclient/simulated package provides an in-memory blockchain so you can write unit tests without running a real node.
import (
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/ethclient/simulated"
)

// Allocate 10 ETH to a test account at genesis
alloc := types.GenesisAlloc{
    testAddr: {Balance: big.NewInt(10e18)},
}

// chainID is always 1337
backend := simulated.NewBackend(alloc)
defer backend.Close()

client := backend.Client() // implements the same interface as *ethclient.Client

// Mine a block explicitly
backend.Commit()
Backend methods:
func NewBackend(alloc types.GenesisAlloc, options ...func(*node.Config, *ethconfig.Config)) *Backend

func (n *Backend) Client() Client       // returns the ethclient-compatible interface
func (n *Backend) Commit() common.Hash  // seal a block and advance the chain
func (n *Backend) Rollback()            // discard pending transactions
func (n *Backend) Fork(parentHash common.Hash) error // simulate a reorg
func (n *Backend) AdjustTime(adjustment time.Duration) error
func (n *Backend) Close() error
The simulated backend always uses chain ID 1337. Transactions must be signed with that chain ID.

Build docs developers (and LLMs) love