Examples

Reading a contract, sending a transaction with a local account, and watching events over a socket.

Path: examples

Third-party documentation. This is independently authored analysis of the public Viem codebase — not the official docs, and not reviewed or endorsed by the Viem team.

Examples

The recurring shapes: read a contract, write through a wallet, watch events. Each example assumes a public client client and, where relevant, a wallet client wallet.

Multicall-style batched reads

Multiple contract reads can be issued concurrently with ordinary promises — the stateless action model means batching is just Promise.all, or the built-in aggregate actions where supported by the endpoint.

Simulate-then-write

The standard safe-write loop: simulateContract to preview the outcome (decoded return value, gas estimate, decoded revert reason if any), then writeContract to submit. UIs typically surface the simulation's revert message before ever spending gas.

Watching events

watchContractEvent subscribes via WebSocket transport when available and falls back to polling logs otherwise; handlers receive fully decoded event arguments typed from the ABI literal.

Error handling

Catch structured errors: contract reverts carry decoded custom-error names and args; RPC errors distinguish rate limits from execution failures. This enables retry policies keyed on error type rather than message text.

Examples

Reading contract state

Reading contract state
typescript
import { createPublicClient, http, erc20Abi } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ chain: mainnet, transport: http() })
 
const symbol = await client.readContract({
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
abi: erc20Abi,
functionName: 'symbol',
})
STATUSexample

readContract encodes the call from the given ABI, performs an eth_call, and decodes the result. Because erc20Abi is a literal type, functionName and its return value are fully typed.

Sending a transaction from a local account

Sending a transaction from a local account
typescript
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
 
const account = privateKeyToAccount('0x...')
const wallet = createWalletClient({ account, chain: mainnet, transport: http() })
 
const hash = await wallet.sendTransaction({
to: '0x0000000000000000000000000000000000000000',
value: parseEther('0.01'),
})
STATUSexample

With a local account attached, viem signs locally and submits via eth_sendRawTransaction; with only an EIP-1193 provider attached, signing is delegated to the injected wallet instead.

Edge Cases

  • Value fields must be passed as bigint wei values — passing a number for large amounts silently loses precision at the type level is prevented, but string amounts are not auto-parsed: use parseEther/parseUnits.
  • readContract performs an eth_call: any state-changing function invoked through it executes in simulation and its effects are discarded.
  • WebSocket transports require explicit reconnection handling on network loss; http transports are stateless but poll-based watchers have block-latency trade-offs.