Examples
Real-world examples showing viem-go in action, with TypeScript comparisons
Real-world examples showing viem-go in action, with TypeScript comparisons
Common read operations you'll reach for in almost every project — querying transactions, blocks, and other on-chain state. Each snippet shows the viem-go call alongside the equivalent TypeScript viem code so you can map between the two.
Fetch the receipt for a mined transaction to inspect its status, gas usage, and the block it landed in.
1txHash := common.HexToHash("0x...")2
3receipt, err := c.GetTransactionReceipt(context.Background(), txHash)4if err != nil {5 log.Fatal(err)6}7
8fmt.Printf("Status: %d\n", receipt.Status)9fmt.Printf("Gas Used: %d\n", receipt.GasUsed)10fmt.Printf("Block: %d\n", receipt.BlockNumber)Interacting with smart contracts is the core of most Ethereum applications. These examples cover reading on-chain state through view functions and encoding calldata for contract writes — the two operations you'll use most often.
Query an ERC-20 contract for its name, symbol, decimals, and total supply. viem-go's built-in ERC-20 bindings make this a single struct — no manual ABI wrangling required.
1import "github.com/ChefBingbong/viem-go/contracts/erc20"2
3usdcAddress := common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")4token, _ := erc20.New(usdcAddress, publicClient)5
6name, _ := token.Name(context.Background())7symbol, _ := token.Symbol(context.Background())8decimals, _ := token.Decimals(context.Background())9totalSupply, _ := token.TotalSupply(context.Background())10
11fmt.Printf("Token: %s (%s)\n", name, symbol)12fmt.Printf("Decimals: %d\n", decimals)13fmt.Printf("Total Supply: %s\n", totalSupply.String())Manually encode calldata from an ABI and arguments. This is useful when you need raw calldata for low-level eth_call or eth_sendTransaction without the higher-level ReadContract/WriteContract helpers.
1import "github.com/ChefBingbong/viem-go/abi"2
3parsed, _ := abi.Parse([]byte(`[{4 "name": "transfer",5 "type": "function",6 "inputs": [7 {"name": "to", "type": "address"},8 {"name": "amount", "type": "uint256"}9 ]10}]`))11
12data, _ := parsed.EncodeFunctionData("transfer",13 common.HexToAddress("0x..."),14 big.NewInt(1000000),15)16
17fmt.Printf("Encoded: 0x%x\n", data)Accounts are how you sign transactions and messages. viem-go supports creating accounts from raw private keys or BIP-39 mnemonics, with the same API shape as viem's accounts module.
Derive an account (address + public key) from a hex-encoded private key. This is the most direct way to create a signer for wallet client operations.
1import "github.com/ChefBingbong/viem-go/accounts"2
3account, _ := accounts.PrivateKeyToAccount("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")4
5fmt.Printf("Address: %s\n", account.Address)6fmt.Printf("Public Key: %s\n", account.PublicKey)Derive an account from a BIP-39 mnemonic phrase. An optional derivation path lets you generate multiple accounts from the same seed.
1import "github.com/ChefBingbong/viem-go/accounts"2
3mnemonic := "test test test test test test test test test test test junk"4
5account, _ := accounts.MnemonicToAccount(mnemonic, nil)6
7fmt.Printf("Address: %s\n", account.Address)Helpers for the low-level operations that come up constantly in Ethereum development — unit conversions between human-readable values and raw integers, hashing, and cryptographic signature recovery.
Convert between human-readable token amounts (like "1.5" ETH) and their raw integer representations (wei). viem-go supports arbitrary decimal precision for any ERC-20 denomination.
1import "github.com/ChefBingbong/viem-go/utils/unit"2
3// Parse ETH to wei4wei, _ := unit.ParseEther("1.5")5fmt.Println("Wei:", wei) // 15000000000000000006
7// Parse USDC (6 decimals)8usdcAmount, _ := unit.ParseUnits("100", 6)9fmt.Println("USDC:", usdcAmount) // 10000000010
11// Format back12ethString := unit.FormatEther(wei)13fmt.Println("ETH:", ethString) // 1.5Keccak256 hashing, EIP-191 message signing, and ecrecover-based address recovery. These are the building blocks for signature verification, permit flows, and off-chain authentication.
1import (2 "github.com/ChefBingbong/viem-go/utils/hash"3 "github.com/ChefBingbong/viem-go/utils/signature"4)5
6// Keccak256 hash7h := hash.Keccak256([]byte("hello"))8fmt.Printf("Hash: 0x%x\n", h)9
10// Hash a message for signing (EIP-191)11messageHash := signature.HashMessage("hello world")12fmt.Printf("Message Hash: 0x%x\n", messageHash)13
14// Recover address from signature15address, _ := signature.RecoverMessageAddress("hello world", sig)16fmt.Printf("Recovered: %s\n", address)Production-grade patterns that go beyond single RPC calls. The snippets below are cherry-picked from viem-go-extractor-demo — a real UniswapV2 pool extractor that heavily exercises multicall batching, concurrent fan-out, reorg-aware log watching, and on-disk caching. These show how viem-go's primitives compose into non-trivial data pipelines.
1// mini-extractor-go/extractor/univ2_extractor.go2// Batch thousands of getReserves calls via Multicall3.3func (ext *UniV2Extractor) batchGetReserves(ctx context.Context, addresses []common.Address) map[string][2]*big.Int {4pairABI := univ2pair.MustParsedABI()5results := make(map[string][2]*big.Int)6
7for i := 0; i < len(addresses); i += multicallBatchSize {8 end := i + multicallBatchSize9 if end > len(addresses) {10 end = len(addresses)11 }12 chunk := addresses[i:end]13
14 contracts := make([]public.MulticallContract, len(chunk))15 for j, addr := range chunk {16 contracts[j] = public.MulticallContract{17 Address: addr,18 ABI: pairABI,19 FunctionName: "getReserves",20 }21 }22
23 mcResults, err := public.Multicall(ctx, ext.client, public.MulticallParameters{24 Contracts: contracts,25 AllowFailure: boolPtr(true),26 })27 if err != nil {28 lib.ExtractorError("batchGetReserves multicall error", "error", err)29 continue30 }31
32 for j, r := range mcResults {33 addrL := strings.ToLower(chunk[j].Hex())34 if r.Status == "success" {35 if vals, ok := r.Result.([]any); ok && len(vals) >= 2 {36 r0, _ := vals[0].(*big.Int)37 r1, _ := vals[1].(*big.Int)38 if r0 != nil && r1 != nil {39 results[addrL] = [2]*big.Int{r0, r1}40 }41 }42 }43 }44}45return results46}