
Viem
- 16 installs
- 4 repo stars
- Updated February 25, 2026
- hairyf/blockchain-master
Interact with Ethereum in TypeScript using viem - Public/Wallet/Test clients, type-safe contract reads/writes, accounts, chains, ENS, and utils.
About
viem is a TypeScript client for Ethereum with Public/Wallet/Test clients, transports, type-safe contract calls, accounts, chains, and ENS. A developer uses it to read and write to Ethereum from TypeScript.
- Public/Wallet/Test clients and HTTP/WebSocket/custom transports
- Type-safe contract reads/writes, accounts, chains, ENS, encoding helpers
Viem by the numbers
- 16 all-time installs (skills.sh)
- Ranked #274 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
- Data as of Jul 13, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hairyf/blockchain-master --skill viemAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 16 |
|---|---|
| repo stars | ★ 4 |
| Last updated | February 25, 2026 |
| Repository | hairyf/blockchain-master ↗ |
What it does
Interact with Ethereum in TypeScript using viem - Public/Wallet/Test clients, type-safe contract reads/writes, accounts, chains, ENS, and utils.
Files
Skill based on viem, generated 2026-02-09. Docs: https://viem.sh
viem is a TypeScript client for Ethereum: Public/Wallet/Test clients, transports (HTTP, WebSocket, custom), type-safe contract reads/writes, local and JSON-RPC accounts, chains, ENS, and encoding/unit helpers.
Core References
| Topic | Description | Reference |
|---|---|---|
| Clients & Transports | Public/Wallet/Test clients, HTTP/WS/custom transports, multicall batching | core-clients-transports |
| Contract | getContract, readContract, writeContract, simulateContract | core-contract |
| Accounts | Local (privateKey, mnemonic) and JSON-RPC accounts, extend with publicActions | core-accounts |
Features
Chains & ENS
| Topic | Description | Reference |
|---|---|---|
| Chains | Built-in chains (viem/chains), defineChain for custom | features-chains |
| ENS | getEnsAddress, getEnsName, getEnsAvatar, normalize | features-ens |
Utilities
| Topic | Description | Reference |
|---|---|---|
| Utilities | getAddress, parseEther/formatEther, encoding, keccak256, ABI helpers | features-utilities |
| ABI | parseAbi, encodeAbiParameters, decodeAbiParameters, getAbiItem | features-abi |
Auth
| Topic | Description | Reference |
|---|---|---|
| SIWE | createSiweMessage, verifySiweMessage, parseSiweMessage, validateSiweMessage | features-siwe |
Public data
| Topic | Description | Reference |
|---|---|---|
| Public Actions | getBalance, getLogs, getBlock, estimateGas, waitForTransactionReceipt, watchEvent | features-public-actions |
Best Practices
| Topic | Description | Reference |
|---|---|---|
| Contract & Errors | Simulate before write, typed error handling, RPC/security | best-practices-contract-and-errors |
External Links
Generation Info
- Source:
sources/viem(https://github.com/wevm/viem) - Git SHA:
4b7585c9cddbb87a746e367f32032cc65a2502ac - Generated: 2026-02-09
- Docs used: site/pages/docs (clients, contract, accounts, chains, ENS, utilities, error-handling)
- More (2 passes): SIWE, ABI, public actions, wallet actions, test actions, blob transactions (site/pages/docs)
Best Practices: Contract Writes & Error Handling
Simulate before write
writeContract sends a transaction and does not validate success. Always use simulateContract first, then pass the returned request to writeContract so parameters match and revert reasons are caught before broadcast.
const { request } = await publicClient.simulateContract({
account,
address,
abi,
functionName: 'transfer',
args: [to, amount],
})
await walletClient.writeContract(request)Typed error handling
Actions export an error type <ActionName>ErrorType. Cast in catch to narrow and handle by error.name (e.g. InternalRpcError, HttpRequestError, ContractFunctionRevertedError).
import type { GetBlockNumberErrorType } from 'viem'
try {
const blockNumber = await client.getBlockNumber()
} catch (e) {
const err = e as GetBlockNumberErrorType
if (err.name === 'HttpRequestError') {
// err.status, err.headers
}
if (err.name === 'ContractFunctionRevertedError') {
// err.data (revert info)
}
}RPC and security
- Use a dedicated RPC URL with
http(url); avoid relying on public fallback to prevent rate limits. - Enable
batch: { multicall: true }on Public Client when doing many reads to reduce RPC/compute usage. - Never commit private keys; use env vars and local accounts only in scripts/tests. In browsers use
custom(provider)(JSON-RPC account).
Key points
- Pair simulateContract with writeContract for every write when possible.
- Use
<Action>ErrorTypein catch and branch onerror.namefor handling. - Use authenticated RPC and multicall batching in production; keep keys out of source.
<!-- Source references:
- https://viem.sh/docs/contract/writeContract
- https://viem.sh/docs/error-handling
-->
Accounts
Accounts provide the signer for Wallet Actions. Two kinds: Local (key on your machine) and JSON-RPC (injected wallet, e.g. MetaMask).
Local accounts
Keys live in your app. Use for scripts, tests, or backend signers.
import { privateKeyToAccount } from 'viem/accounts'
import { mnemonicToAccount } from 'viem/accounts'
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...' as `0x${string}`)
// or from mnemonic
const accountFromMnemonic = mnemonicToAccount('legal winner thank year...')Use with Wallet Client: pass account into each action or set it on the client so you don't pass it every time.
const client = createWalletClient({
chain: mainnet,
transport: http(),
account, // optional: hoist so actions use it by default
})
const hash = await client.sendTransaction({
to: '0xa5cc...',
value: parseEther('0.01'),
// account not needed if hoisted
})JSON-RPC account (browser wallet)
For MetaMask / WalletConnect, use a Wallet Client with custom(provider) and get the account from the provider (e.g. getAddresses()), then pass that account into Wallet Actions. No private key in your code.
Extend Wallet Client with Public Actions
When using a local account, you often need both Wallet and Public clients with the same chain/transport. You can extend the Wallet Client with Public Actions to use one client for both:
import { createWalletClient, http, publicActions } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
const client = createWalletClient({
account,
chain: mainnet,
transport: http(),
}).extend(publicActions)
const blockNumber = await client.getBlockNumber()
const hash = await client.sendTransaction({ to: '0x...', value: 0n })Key points
- Local:
privateKeyToAccount,mnemonicToAccount,hdKeyToAccountfromviem/accounts. - JSON-RPC: use
custom(provider)andgetAddresses()(or similar) for the account. - Hoist
accounton the Wallet Client to avoid passing it to every action. - Use
.extend(publicActions)on the Wallet Client when you need both read and write with one client.
<!-- Source references:
- https://viem.sh/docs/accounts/local
- https://viem.sh/docs/accounts/local/privateKeyToAccount
- https://viem.sh/docs/accounts/jsonRpc
-->
Clients & Transports
Clients expose Actions; transports execute RPC requests. Use Public Client for reads, Wallet Client for signing/sending, Test Client for local dev (Anvil).
Client types
- Public Client:
getBlockNumber,getBalance,readContract, logs, etc. - Wallet Client:
sendTransaction,signMessage,signTypedData, wallet actions. - Test Client:
mine,impersonateAccount,setBalance, etc. (for Anvil).
Usage
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({
chain: mainnet,
transport: http('https://eth.llamarpc.com'),
})
const walletClient = createWalletClient({
chain: mainnet,
transport: http(), // or custom(window.ethereum) for browser
})Public Client supports multicall batching: set batch: { multicall: true } so readContract calls are aggregated into a single aggregate3 request (reduces RPC calls and compute units).
Transports
- HTTP:
http(url?, { batch: true, fetchOptions })— default for RPC. Use a dedicated RPC URL to avoid rate limits. - WebSocket:
webSocket(url)— for subscriptions (watchBlockNumber,watchEvent, etc.). - Custom (EIP-1193):
custom(provider)— inject wallet provider (window.ethereumor WalletConnect). - IPC:
ipc(path)— Node.js only, for local nodes. - Fallback:
fallback([http(url1), http(url2)])— try transports in order.
Key points
- Always pass an RPC URL to
http()in production; omit only for public fallback. - Use
custom(provider)for wallet actions in browsers. - Enable
batch.multicallon Public Client when doing manyreadContractcalls. - Wallet Client needs an account for signing; pass
accountper action or setaccounton the client.
<!-- Source references:
- https://viem.sh/docs/clients/intro
- https://viem.sh/docs/clients/public
- https://viem.sh/docs/clients/transports/http
-->
Contract: getContract, read, write, simulate
Type-safe contract interaction via getContract (instance) or standalone readContract / writeContract / simulateContract.
getContract (instance)
Creates a contract instance with address, abi, and client (Public and/or Wallet). Use when you repeatedly call the same contract.
import { getContract } from 'viem'
import { publicClient, walletClient } from './client'
import { erc20Abi } from './abi'
const contract = getContract({
address: '0x...',
abi: erc20Abi,
client: { public: publicClient, wallet: walletClient },
})
const balance = await contract.read.balanceOf(['0xa5cc...'])
const hash = await contract.write.transfer(['0xa5cc...', 100n], { account })
const unwatch = contract.watchEvent.Transfer({}, { onLogs: (logs) => console.log(logs) })Instance methods: read.*, write.*, simulate.*, estimateGas.*, getEvents.*, watchEvent.*, createEventFilter.
readContract
Read-only (view/pure) calls; no gas, no account. Use Public Client.
const totalSupply = await publicClient.readContract({
address: '0x...',
abi: erc20Abi,
functionName: 'totalSupply',
})
const balance = await publicClient.readContract({
address: '0x...',
abi: erc20Abi,
functionName: 'balanceOf',
args: ['0xa5cc...'],
})writeContract & simulateContract
Write functions change state and require gas; need Wallet Client and account. Always simulate before sending to validate success.
const { request } = await publicClient.simulateContract({
account,
address: '0x...',
abi: erc20Abi,
functionName: 'transfer',
args: ['0xa5cc...', 100n],
})
await walletClient.writeContract(request)Use simulateContract to get the request object, then pass it to writeContract so the same params are used and errors are caught before broadcast.
Key points
- Use getContract when you have a fixed contract and want
contract.read.*/contract.write.*without repeating address/abi. - Use readContract for one-off reads or when you don't need an instance.
- Pair simulateContract with writeContract; never send a write without simulating first when possible.
- ABI types are inferred;
argsand return types come from the ABI.
<!-- Source references:
- https://viem.sh/docs/contract/getContract
- https://viem.sh/docs/contract/readContract
- https://viem.sh/docs/contract/writeContract
- https://viem.sh/docs/contract/simulateContract
-->
ABI
Parse human-readable ABI, encode/decode parameters, and look up ABI items. Used by contract helpers and for low-level call/event data.
Parsing
- parseAbi(signatures[]): Human-readable ABI → JSON
Abi. Use for full contract ABI.
import { parseAbi } from 'viem'
const abi = parseAbi([
'function balanceOf(address owner) view returns (uint256)',
'event Transfer(address indexed from, address indexed to, uint256 value)',
])- parseAbiItem(signature): Single function/event/error signature → one ABI item.
- parseAbiParameters(signature): Human-readable params string (e.g.
'string x, uint y') →AbiParameter[]. - parseAbiParameter(signature): Single parameter string → one
AbiParameter.
Encode / decode
- encodeAbiParameters(params, values): Encode values to hex per ABI spec.
paramsareAbiParameter[](e.g. frominputs/outputs); use parseAbiParameters for human-readable. - decodeAbiParameters(params, data): Decode hex
datainto decoded values; types inferred fromparams. - encodePacked: Tight packing (no padding) for non-ABI use (e.g. hashing).
import { encodeAbiParameters, decodeAbiParameters, parseAbiParameters } from 'viem'
const encoded = encodeAbiParameters(
parseAbiParameters('string x, uint y, bool z'),
['wagmi', 420n, true]
)
const decoded = decodeAbiParameters(
parseAbiParameters('string x, uint y, bool z'),
encoded
)
// ['wagmi', 420n, true]Lookup
- getAbiItem({ abi, name, args? }): Get one item from an ABI by name (or 4-byte selector). Use
argsto disambiguate overloads.
import { getAbiItem } from 'viem'
const item = getAbiItem({ abi, name: 'balanceOf', args: ['0x...'] })Relation to contract APIs
- encodeFunctionData / decodeFunctionResult use these under the hood for call data.
- encodeEventTopics / decodeEventLog use them for event filters and log decoding.
- Prefer readContract / writeContract when you have a full ABI; use raw encode/decode when building custom payloads or decoding arbitrary calldata.
Key points
- Use parseAbi or parseAbiItem for type-safe, human-readable ABI in code.
- encodeAbiParameters / decodeAbiParameters match the Solidity ABI spec; use for cross-contract or off-chain encoding.
- getAbiItem is useful when you have a large ABI and need one function or event by name or selector.
<!-- Source references:
- https://viem.sh/docs/abi/parseAbi
- https://viem.sh/docs/abi/encodeAbiParameters
- https://viem.sh/docs/abi/decodeAbiParameters
- https://viem.sh/docs/abi/getAbiItem
-->
Blob Transactions (EIP-4844)
Send and work with blob transactions: large binary payloads (~128KB per blob) that are not EVM-accessible; only commitments are on-chain. Blobs are transient (~18 days). Use for rollup data, attestations, or large off-chain data references.
Sending a blob transaction
1. Setup KZG: Use a KZG implementation (e.g. c-kzg, kzg-wasm) and setupKzg(bindings, trustedSetupPath). Node: use mainnetTrustedSetupPath from viem/node. 2. Create blobs: toBlobs({ data }) — pass hex or bytes; returns array of blob hex. Use stringToHex for string data. 3. Send: Call walletClient.sendTransaction({ account, blobs, kzg, to?, maxFeePerBlobGas?, ... }). Chain must support EIP-4844.
import { toBlobs, setupKzg, stringToHex, parseGwei } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
import * as cKzg from 'c-kzg'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
const blobs = toBlobs({ data: stringToHex('hello world') })
const hash = await walletClient.sendTransaction({
account,
blobs,
kzg,
maxFeePerBlobGas: parseGwei('30'),
to: '0x...',
})Utilities
- toBlobs({ data }): Encode data into one or more blob hex values.
- fromBlobs({ blobs }): Decode blob array back to single hex (for data you encoded with toBlobs).
- blobsToCommitments, blobsToProofs: Blob → commitments/proofs (used internally for tx serialization).
- commitmentToVersionedHash, commitmentsToVersionedHashes: Commitment → versioned hash (e.g. for log indexing).
- sidecarsToVersionedHashes, toBlobSidecars: Sidecar/versioned-hash helpers.
- setupKzg(bindings, trustedSetupPath): Create KZG instance for the client. defineKzg for custom setup.
Fee
- getBlobBaseFee: Public action to get current blob base fee.
- maxFeePerBlobGas: Pass in sendTransaction for blob tx; otherwise estimated if supported.
Key points
- Blob transactions require a Wallet Client with account, blobs, and kzg. No KZG needed for reading blob hashes or decoding data you already have.
- Use toBlobs for payloads; fromBlobs only for data you encoded. For generic blob content (e.g. from another source), decode according to that format.
- Blobs are not stored long-term; use external storage or indexers if you need persistence beyond the blob window.
<!-- Source references:
- https://viem.sh/docs/guides/blob-transactions
- https://viem.sh/docs/utilities/toBlobs
- https://viem.sh/docs/utilities/fromBlobs
- https://viem.sh/docs/utilities/setupKzg
-->
Chains
Clients are configured with a chain (id, name, RPC URLs, block explorers, optional contracts like multicall). Use viem/chains for built-in chains or defineChain for custom ones.
Built-in chains
import { mainnet, polygon, base, zora } from 'viem/chains'
import { createPublicClient, http } from 'viem'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})Full list: mainnet, sepolia, polygon, arbitrum, optimism, base, zora, etc.
Custom chain
Use defineChain when the chain is not in viem. Include rpcUrls, blockExplorers, and for multicall batching include contracts.multicall3.
import { defineChain } from 'viem'
export const myChain = defineChain({
id: 7777777,
name: 'My Chain',
nativeCurrency: { decimals: 18, name: 'Ether', symbol: 'ETH' },
rpcUrls: {
default: { http: ['https://rpc.example.com'], webSocket: ['wss://rpc.example.com'] },
},
blockExplorers: {
default: { name: 'Explorer', url: 'https://explorer.example.com' },
},
contracts: {
multicall3: {
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
blockCreated: 1,
},
},
})Key points
- Pass
chaintocreatePublicClient/createWalletClientso RPC and formatters match the network. - Custom chains need correct
idandrpcUrls; addcontracts.multicall3if you use Public Client multicall. - Chain-specific config (e.g. fees, formatters) can be set on the chain object for advanced use.
<!-- Source references:
- https://viem.sh/docs/chains/introduction
- https://viem.sh/docs/chains/fees
-->
ENS
Resolve ENS names on mainnet (or L1 with Universal Resolver). Use normalize before resolving to comply with UTS-46.
Actions (Public Client)
- getEnsAddress: name → address. Use
normalize(name)first. - getEnsName: address → primary name.
- getEnsAvatar: name → avatar URL.
- getEnsResolver / getEnsText: resolver and text records.
import { normalize } from 'viem/ens'
const address = await publicClient.getEnsAddress({ name: normalize('wevm.eth') })
const name = await publicClient.getEnsName({ address: '0xd2135...' })
const avatar = await publicClient.getEnsAvatar({ name: normalize('wevm.eth') })Chain-specific resolution (ENSIP-19): pass coinType to getEnsAddress when the client is on mainnet.
Utilities
- normalize (
viem/ens): UTS-46 normalize ENS names before passing to actions. - namehash / labelhash: hash name/label for contract calls.
Key points
- Client should be on mainnet (or L1 with ENS) for resolution.
- Always normalize names with
normalize()fromviem/ensto avoid invalid characters and casing issues. - Use
getEnsAddressfor name→address;getEnsNamefor address→name;getEnsAvatarfor avatar URL.
<!-- Source references:
- https://viem.sh/docs/ens/actions/getEnsAddress
- https://viem.sh/docs/ens/utilities/normalize
-->
Public Actions
Actions that map one-to-one to public Ethereum RPC methods. Used with a Public Client; no signing, no special permissions. Use for reading chain state, logs, blocks, and transaction status.
Account & balance
- getBalance({ address, blockNumber?, blockTag? }): Balance in wei. Use formatEther for display.
- getTransactionCount({ address, blockNumber?, blockTag? }): Nonce for the address.
Block
- getBlockNumber(): Current block number.
- getBlock({ blockNumber?, blockTag?, includeTransactions? }): Block header and optional transactions.
- getBlockTransactionCount({ blockNumber?, blockTag? }): Number of transactions in a block.
- watchBlockNumber, watchBlocks: Subscribe to new blocks (requires WebSocket transport).
Transaction status
- getTransaction({ hash }): Transaction by hash.
- getTransactionReceipt({ hash }): Receipt (status, logs, gasUsed).
- getTransactionConfirmations({ hash }): Number of confirmations.
- waitForTransactionReceipt({ hash, confirmations?, timeout? }): Wait until receipt (and optional confirmations).
- watchPendingTransactions: Subscribe to pending tx hashes (WebSocket).
Logs and events
- getLogs({ address?, event?, events?, args?, fromBlock?, toBlock?, blockHash?, strict? }): Event logs. Scope by contract address, event (or events), indexed args, and block range. Use parseAbiItem for human-readable event.
- createEventFilter, getFilterChanges, getFilterLogs, uninstallFilter: Polling-based log filters.
- watchEvent({ address?, event?, events?, args?, onLogs }): Subscribe to logs (WebSocket).
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { from: '0x...' },
fromBlock: 16330000n,
toBlock: 16330050n,
})Fee and gas
- getGasPrice(): Current gas price.
- estimateFeesPerGas(): EIP-1559 maxFeePerGas / maxPriorityFeePerGas.
- estimateGas({ account?, data?, to?, value?, ... }): Estimate gas for a call or transaction.
- getFeeHistory({ blockCount, newestBlock, rewardPercentiles? }): Historical fee data.
- getBlobBaseFee(): Blob base fee (EIP-4844).
Call and proof
- call({ account?, data?, to?, value?, blockNumber?, blockTag? }): Raw eth_call.
- createAccessList({ account?, data?, to?, ... }): Build access list for a call.
- getProof({ address, storageKeys, blockNumber?, blockTag? }): Merkle proof for account/storage.
Chain and EIP-712
- getChainId(): Current chain ID.
- getEip712Domain({ contractAddress }): EIP-712 domain for a contract.
Key points
- Public actions are read-only and do not require an account; pass account only where needed (e.g. estimateGas for a state-changing call).
- For subscriptions (watchBlockNumber, watchEvent, watchPendingTransactions) use a transport that supports subscriptions (e.g. webSocket).
- getLogs with event + args + block range is the standard way to query historical events; use watchEvent for real-time logs.
<!-- Source references:
- https://viem.sh/docs/actions/public/introduction
- https://viem.sh/docs/actions/public/getBalance
- https://viem.sh/docs/actions/public/getLogs
- https://viem.sh/docs/actions/public/getTransactionReceipt
- https://viem.sh/docs/actions/public/waitForTransactionReceipt
-->
SIWE (Sign-In with Ethereum)
EIP-4361 Sign-In with Ethereum: create messages, verify signatures, parse and validate. Use for wallet-based auth flows.
Import
import { createSiweMessage, generateSiweNonce, parseSiweMessage, validateSiweMessage } from 'viem/siwe'Server-side verification uses the Public Client action verifySiweMessage.
Create message
- createSiweMessage({ address, chainId, domain, nonce, uri, version, ... }): Build EIP-4361 formatted string. Required:
address,chainId,domain,nonce,uri,version: '1'. Optional:statement,expirationTime,issuedAt,notBefore,resources,scheme,requestId. - generateSiweNonce(): Random nonce for replay protection; use when creating the message on the server.
import { createSiweMessage, generateSiweNonce } from 'viem/siwe'
const message = createSiweMessage({
address: account.address,
chainId: mainnet.id,
domain: 'example.com',
nonce: generateSiweNonce(),
uri: 'https://example.com/login',
version: '1',
statement: 'Sign in to Example',
})
// User signs `message` with walletClient.signMessage({ account, message })Verify (server)
- publicClient.verifySiweMessage({ message, signature, address?, domain?, nonce?, ... }): Returns
boolean. Use after receiving the signed message. Optional filters:address,domain,nonce,scheme,time,blockNumber/blockTag(for smart contract signers).
const valid = await publicClient.verifySiweMessage({ message, signature })Parse and validate
- parseSiweMessage(message): Parse EIP-4361 string into a
SiweMessageobject (address, chainId, domain, nonce, etc.). - validateSiweMessage(message): Validate message fields (format, expiration, notBefore); throws if invalid.
Key points
- Always use generateSiweNonce() on the server when issuing a message; verify the same nonce in verifySiweMessage to prevent replay.
- For contract accounts, pass blockNumber or blockTag so viem can check the contract existed at that block.
- Use strict validation (expirationTime, notBefore) when creating the message so verifySiweMessage can enforce time bounds via the
timeparameter.
<!-- Source references:
- https://viem.sh/docs/siwe/utilities/createSiweMessage
- https://viem.sh/docs/siwe/actions/verifySiweMessage
- https://viem.sh/docs/siwe/utilities/parseSiweMessage
- https://viem.sh/docs/siwe/utilities/validateSiweMessage
-->
Test Actions
Actions that map to test/mining RPC methods (e.g. Anvil). Used with a Test Client over a local node. Essential for tests and simulations without real balance or mainnet.
Account
- impersonateAccount({ address }): Act as
addressfor subsequent calls (no private key). - stopImpersonatingAccount({ address }): Stop impersonation.
- setBalance({ address, value }): Set account balance in wei.
- setCode({ address, code }): Set contract code at address.
- setNonce({ address, nonce }): Set nonce.
- setStorageAt({ address, index, value }): Set storage slot.
Block
- mine({ blocks?, timestamp? }): Mine one or more blocks.
- setAutomine({ mode }): Turn automine on/off.
- setIntervalMining({ interval }): Mine every N seconds.
- increaseTime({ seconds }): Increase next block timestamp.
- setNextBlockTimestamp({ timestamp }): Set exact next block time.
- setBlockTimestampInterval({ interval }), removeBlockTimestampInterval: Block time delta.
- setBlockGasLimit({ gasLimit }), setNextBlockBaseFeePerGas: Gas limits/fees for next block.
State
- snapshot(): Create state snapshot; returns snapshot ID.
- revert({ id }): Revert to snapshot.
- dumpState(): Dump state to hex; use with loadState to restore later.
- loadState({ state }): Load state from dumpState output.
- reset({ jsonRpcUrl?, blockNumber? }): Reset chain state (e.g. re-fork).
Transaction / node
- dropTransaction({ hash }): Remove tx from pool.
- getTxpoolContent(), getTxpoolStatus(), inspectTxpool(): Inspect mempool.
- sendUnsignedTransaction({ ... }): Send unsigned tx (for impersonated account).
- setCoinbase({ address }), setMinGasPrice: Node/miner settings.
- setLoggingEnabled({ enabled }), setRpcUrl({ url }): Debug/config.
Key points
- Use createTestClient (or test client from createPublicClient + createWalletClient with Anvil transport) and point transport at Anvil (e.g.
http('http://127.0.0.1:8545')). - impersonateAccount + setBalance lets you send txs from any address in tests.
- snapshot / revert isolate test cases without restarting the node; dumpState / loadState for cross-session state reuse.
<!-- Source references:
- https://viem.sh/docs/actions/test/introduction
- https://viem.sh/docs/actions/test/impersonateAccount
- https://viem.sh/docs/actions/test/setBalance
- https://viem.sh/docs/actions/test/mine
- https://viem.sh/docs/actions/test/snapshot
-->
Utilities
Common helpers: address checksum, hex/bytes conversion, hashing, and unit formatting.
Address
- getAddress(address): EIP-55 checksum; use for consistent
Addresstype. - isAddress(value): type guard for valid address string.
- isAddressEqual(a, b): constant-time equality.
Units (wei ↔ display)
- parseEther("1.5") → wei
bigint(18 decimals). - formatEther(wei) → string.
- parseUnits(value, decimals) / formatUnits(value, decimals) for arbitrary decimals (e.g. 6 for USDC).
- parseGwei / formatGwei for gas price.
import { parseEther, formatEther, parseUnits, formatUnits } from 'viem'
parseEther('1') // 1000000000000000000n
formatEther(1000n) // '0.000000000000001'
parseUnits('100', 6) // 100000000n (e.g. USDC)Data & encoding
- toHex / fromHex: bytes ↔ hex string.
- toBytes / fromBytes: bytes ↔ Uint8Array.
- concat(hex[]): concatenate hex.
- slice(hex, start?, end?), pad(hex, size), trim(hex).
Hash
- keccak256(data), sha256(data) (bytes or hex).
- hashMessage(message) for EIP-191 personal sign.
- toFunctionSelector(signature), toEventSignature(event) for ABI selectors.
ABI encoding (low-level)
- encodeFunctionData, decodeFunctionResult: call data.
- encodeEventTopics, decodeEventLog: event filters and log decoding.
- parseAbi, parseAbiItem, getAbiItem: parse ABI strings.
Key points
- Use getAddress when storing or comparing addresses to get checksummed
Address. - Use parseEther / formatEther for ETH; parseUnits / formatUnits for tokens with custom decimals.
- Use keccak256 / hashMessage for hashes; toFunctionSelector for contract call encoding.
<!-- Source references:
- https://viem.sh/docs/utilities/getAddress
- https://viem.sh/docs/utilities/parseEther
- https://viem.sh/docs/utilities/keccak256
- https://viem.sh/docs/abi/encodeFunctionData
-->
Wallet Actions
Actions that require wallet/signer and map to wallet RPC methods. Used with a Wallet Client; need an account (local or JSON-RPC). Use for sending transactions, signing, and chain switching.
Account
- getAddresses(): Connected addresses (from EIP-1193 provider).
- requestAddresses(): Request account access (e.g. MetaMask connect).
Transaction
- sendTransaction({ account, to, value?, data?, gas?, maxFeePerGas?, maxPriorityFeePerGas?, nonce?, chain?, blobs?, kzg?, ... }): Create, sign, and send; returns tx hash. With blobs + kzg sends a blob transaction (EIP-4844).
- sendTransactionSync: Same, returns hash synchronously where the transport supports it.
- signTransaction({ account, to, ... }): Sign without sending; returns serialized signed tx.
- prepareTransactionRequest({ account, to?, data?, value?, ... }): Build transaction request (e.g. fill gas) without sending. Use with sendRawTransaction or signTransaction.
- sendRawTransaction({ serializedTransaction }): Broadcast a signed serialized tx.
Signing
- signMessage({ account, message }): EIP-191 personal sign; returns hex signature.
- signTypedData({ account, domain, types, primaryType, message }): EIP-712 typed data sign.
Chain
- switchChain({ id }): Ask wallet to switch to chain ID.
- addChain({ chain }): Add and optionally switch to a chain.
EIP-5792 (wallet call bundles)
- sendCalls({ account, calls }): Send a bundle of calls (batch) via supporting wallets.
- getCallsStatus({ id }), waitForCallsStatus, showCallsStatus: Status of a call bundle.
- getCapabilities({ account }): Check wallet capabilities (e.g. supports
wallet_sendCalls).
Key points
- Pass account per action or set account on the Wallet Client (account hoisting) so you don’t pass it every time.
- Use prepareTransactionRequest when you need to inspect or modify the request (e.g. gas) before signing/sending.
- For blob transactions, pass blobs (from toBlobs) and kzg (from setupKzg) to sendTransaction; chain must support EIP-4844.
<!-- Source references:
- https://viem.sh/docs/actions/wallet/introduction
- https://viem.sh/docs/actions/wallet/sendTransaction
- https://viem.sh/docs/actions/wallet/signMessage
- https://viem.sh/docs/actions/wallet/prepareTransactionRequest
-->