viem-goviem-go

Public Client

Read-only access to the Ethereum blockchain through standard JSON-RPC methods

A Public Client provides read-only access to the Ethereum blockchain through standard JSON-RPC methods like eth_blockNumber, eth_getBalance, eth_call, and more.

The CreatePublicClient function sets up a Public Client with a given Transport and optional Chain.

Import

import (
"github.com/ChefBingbong/viem-go/client"
"github.com/ChefBingbong/viem-go/client/transport"
"github.com/ChefBingbong/viem-go/chain/definitions"
)

These are the most common imports for setting up a Public Client:

  • client: Client constructors and types (e.g. CreatePublicClient, PublicClientConfig, BlockTag* constants).
  • transport: Transport factories for JSON-RPC (e.g. transport.HTTP(...), transport.WebSocket(...)).
  • definitions: Prebuilt chain definitions (e.g. definitions.Mainnet). Optional, but recommended.

Import additional packages only when you need them:

  • common: Address/hash helpers from go-ethereum (e.g. common.HexToAddress("0x...")).
  • public: Public actions & watch parameter types (e.g. public.WatchBlockNumberParameters).

Go notes

Closing the client

In viem-go, publicClient.Close() closes the underlying transport connection (especially important for WebSocket transports). It’s idiomatic to call it with defer right after successful construction.

Passing a context

Public Client methods and watch actions accept a context.Context as the first argument (e.g. publicClient.GetBalance(ctx, ...), publicClient.WatchBlockNumber(ctx, ...)). Use it to cancel requests or to set timeouts with context.WithTimeout.

Error handling

Most viem-go APIs return (value, error). Always handle errors from CreatePublicClient and from each call.

import (
"context"
"log"
"time"
"github.com/ChefBingbong/viem-go/client"
"github.com/ChefBingbong/viem-go/client/transport"
"github.com/ChefBingbong/viem-go/chain/definitions"
)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})
if err != nil {
log.Fatal(err)
}
defer func() { _ = publicClient.Close() }()
blockNumber, err := publicClient.GetBlockNumber(ctx)
if err != nil {
log.Fatal(err)
}
_ = blockNumber

Usage

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})
if err != nil {
log.Fatal(err)
}
defer publicClient.Close()

WebSocket Transport (subscriptions)

Watch actions will poll on HTTP transports and can use subscriptions when a WebSocket transport is configured. For details on WebSocket configuration, see WebSocket Transport.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Chain: definitions.Mainnet,
Transport: transport.WebSocket("wss://eth.llamarpc.com"),
})
if err != nil {
log.Fatal(err)
}
defer publicClient.Close()
WebSocket transports enable real eth_subscribe subscriptions for watch actions, while HTTP transports fall back to polling. Prefer WebSocket for watch-heavy workloads to reduce latency and RPC calls.

Watch actions (brief)

The Public Client exposes watch helpers like WatchBlockNumber that stream events over a channel. Cancel the context to stop watching.

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
events := publicClient.WatchBlockNumber(ctx, public.WatchBlockNumberParameters{
EmitOnBegin: true,
})
for event := range events {
fmt.Println(event.BlockNumber)
}

Parameters

Transport (required)

  • Type: transport.TransportFactory

Transport factory for JSON-RPC calls. This parameter is required.

If your transport needs its own configuration, keep it in the transport constructor and refer to transport docs (e.g. HTTP Transport or WebSocket Transport).

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})

Chain (optional)

  • Type: *chain.Chain

The Chain configuration (e.g. definitions.Mainnet) for the Public Client.

This influences defaults like PollingInterval (based on block time) and is used by some actions for chain-aware behavior. See Clients & Transports.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})

Batch (optional)

  • Type: *client.BatchOptions

Batch settings for the client (e.g. enabling multicall-style batching for some actions).

If you don’t need batching, omit this field.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Batch: &client.BatchOptions{
Multicall: &client.MulticallBatchOptions{},
},
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})
Multicall batching (action-level) is separate from transport-level JSON-RPC batching. Both can be used together -- multicall aggregates contract reads into one eth_call, while JSON-RPC batching combines multiple RPC requests into a single HTTP request.

PollingInterval (optional)

  • Type: time.Duration
  • Default: min(max(chain.BlockTime/2, 500ms), 4s) (defaults to 4s when Chain is not provided)

Frequency for polling-enabled behavior, including watch actions when not using subscriptions.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
PollingInterval: 10 * time.Second,
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})

CacheTime (optional)

  • Type: time.Duration
  • Default: PollingInterval

Time that cached data will remain in memory.

In viem-go, if CacheTime is not set, it defaults to the client PollingInterval.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
CacheTime: 10 * time.Second,
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})

ExperimentalBlockTag (optional)

  • Type: client.BlockTag
  • Default: client.BlockTagLatest

Default block tag used by actions when you don’t pass an explicit block tag.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
ExperimentalBlockTag: client.BlockTagSafe,
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})
Changing the default block tag to anything other than latest (e.g. safe or finalized) may cause unexpected behavior with certain RPC providers that don't fully support these tags. Test with your provider before deploying.

Key (optional)

  • Type: string
  • Default: "public"

A key for the Client.

This is primarily useful when you have multiple clients in the same process and want a stable identifier for debugging, logging, or internal bookkeeping.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Key: "foo",
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})

Name (optional)

  • Type: string
  • Default: "Public Client"

A human-readable name for the Client.

This is useful for debugging and for distinguishing multiple client instances in your application.

publicClient, err := client.CreatePublicClient(client.PublicClientConfig{
Name: "Foo Public Client",
Chain: definitions.Mainnet,
Transport: transport.HTTP("https://eth.llamarpc.com"),
})

Return Type

CreatePublicClient returns (*PublicClient, error).