viem
$
npx mdskill add TerminalSkills/skills/viemExecute type-safe Ethereum transactions and read blockchain data.
- Build dApps that send transactions and interact with smart contracts.
- Integrates with Ethereum RPC nodes and uses TypeScript ABIs.
- Decides actions by parsing chain data and validating transaction inputs.
- Delivers results through zero-dependency modules and tree-shakeable code.
SKILL.md
.github/skills/viemView on GitHub ↗
---
name: viem
description: >-
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.
license: Apache-2.0
compatibility: ''
metadata:
author: terminal-skills
version: 1.0.0
category: Blockchain & Web3
tags:
- ethereum
- typescript
- web3
- rpc
- smart-contracts
- type-safe
- wagmi
---
# 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
```typescript
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
```typescript
// 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
```typescript
// 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
```typescript
// 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
```typescript
// ENS name → address
const address = await publicClient.getEnsAddress({ name: "vitalik.eth" });
// Address → ENS name
const name = await publicClient.getEnsName({
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
});
```
## Installation
```bash
npm install viem
```
## Best Practices
1. **ABI as const** — Declare ABIs with `as const` for full type inference on function names, args, and return types
2. **Separate clients** — Use `publicClient` for reads (free), `walletClient` for writes (costs gas)
3. **waitForTransactionReceipt** — Always wait for receipt after sending; don't assume success from hash alone
4. **parseEther/formatEther** — Use viem's utilities for ETH conversions; never do manual decimal math with bigint
5. **Chain configuration** — Import chains from `viem/chains`; includes RPC URLs, block explorer, native currency
6. **Error handling** — Viem throws typed errors; catch `ContractFunctionRevertedError` for contract reverts
7. **Batch requests** — Use `multicall` to batch multiple contract reads into one RPC call; reduces latency
8. **Works with wagmi** — Viem is the core of wagmi (React hooks for Ethereum); same patterns, same types
More from TerminalSkills/skills