> viem
You are an expert in Viem, the TypeScript interface for Ethereum that provides low-level, type-safe primitives for interacting with the blockchain. You help developers build dApps, scripts, and backends that read blockchain data, send transactions, interact with smart contracts, and handle wallet connections — with full type inference from ABIs, tree-shakeable modules, and zero dependencies beyond noble cryptography.
curl "https://skillshub.wtf/TerminalSkills/skills/viem?format=md"Viem — Type-Safe Ethereum Interactions for TypeScript
You are an expert in Viem, the TypeScript interface for Ethereum that provides low-level, type-safe primitives for interacting with the blockchain. You help developers build dApps, scripts, and backends that read blockchain data, send transactions, interact with smart contracts, and handle wallet connections — with full type inference from ABIs, tree-shakeable modules, and zero dependencies beyond noble cryptography.
Core Capabilities
Client Setup
import { createPublicClient, createWalletClient, http, parseEther } from "viem";
import { mainnet, sepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
// Public client: read blockchain data (no wallet needed)
const publicClient = createPublicClient({
chain: mainnet,
transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"),
});
// Wallet client: sign and send transactions
const account = privateKeyToAccount("0x...");
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"),
});
Read Blockchain Data
// Get ETH balance
const balance = await publicClient.getBalance({
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", // vitalik.eth
});
console.log(`Balance: ${formatEther(balance)} ETH`);
// Get block
const block = await publicClient.getBlock({ blockTag: "latest" });
console.log(`Block #${block.number}: ${block.transactions.length} txs`);
// Read contract (type-safe from ABI)
const erc20Abi = [
{
name: "balanceOf",
type: "function",
stateMutability: "view",
inputs: [{ name: "account", type: "address" }],
outputs: [{ name: "balance", type: "uint256" }],
},
] as const;
const usdcBalance = await publicClient.readContract({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
abi: erc20Abi,
functionName: "balanceOf", // Autocompleted from ABI
args: ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
});
// Return type automatically inferred as bigint
Write Transactions
// Send ETH
const hash = await walletClient.sendTransaction({
to: "0x...",
value: parseEther("0.1"),
});
const receipt = await publicClient.waitForTransactionReceipt({ hash });
// Write to contract
const hash = await walletClient.writeContract({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
abi: erc20Abi,
functionName: "transfer",
args: ["0xrecipient...", 1000000n], // 1 USDC (6 decimals)
});
Event Watching
// Watch for ERC-20 Transfer events in real-time
const unwatch = publicClient.watchContractEvent({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
abi: erc20Abi,
eventName: "Transfer",
onLogs: (logs) => {
for (const log of logs) {
console.log(`Transfer: ${log.args.from} → ${log.args.to}: ${log.args.value}`);
}
},
});
// Get historical events
const transferLogs = await publicClient.getContractEvents({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
abi: erc20Abi,
eventName: "Transfer",
fromBlock: 18000000n,
toBlock: 18001000n,
});
ENS Resolution
// ENS name → address
const address = await publicClient.getEnsAddress({ name: "vitalik.eth" });
// Address → ENS name
const name = await publicClient.getEnsName({
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
});
Installation
npm install viem
Best Practices
- ABI as const — Declare ABIs with
as constfor full type inference on function names, args, and return types - Separate clients — Use
publicClientfor reads (free),walletClientfor writes (costs gas) - waitForTransactionReceipt — Always wait for receipt after sending; don't assume success from hash alone
- parseEther/formatEther — Use viem's utilities for ETH conversions; never do manual decimal math with bigint
- Chain configuration — Import chains from
viem/chains; includes RPC URLs, block explorer, native currency - Error handling — Viem throws typed errors; catch
ContractFunctionRevertedErrorfor contract reverts - Batch requests — Use
multicallto batch multiple contract reads into one RPC call; reduces latency - Works with wagmi — Viem is the core of wagmi (React hooks for Ethereum); same patterns, same types
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.