# Viem

> This skill should be used when the user asks about "viem", "viem client", "viem actions", "TypeScript Ethereum", "createPublicClient", "createWalletClient", "parseEther", "formatEther", "readContract", "writeContract", or mentions using viem for blockchain interactions.

- Skill: `sablier-labs/viem` (Agent Skill)
- Install (CLI): `npx skillmds@latest add sablier-labs/viem`
- Raw SKILL.md: https://api.skillmd.com/api/skills/sablier-labs/viem/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: sablier-labs (https://skillmd.com/u/sablier-labs)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/sablier-labs/viem

---


# Viem

## Overview

Viem is a TypeScript interface for Ethereum that provides low-level stateless primitives for interacting with the blockchain. It focuses on developer experience, stability, bundle size, and performance.

Key features:

- Automatic type safety and inference
- Tree-shakable lightweight modules
- Optimized encoding/parsing
- Composable APIs

## Core Concepts

| Concept        | Description                                                   |
| -------------- | ------------------------------------------------------------- |
| **Clients**    | `PublicClient`, `WalletClient`, `TestClient` - entry points   |
| **Transports** | Connection layer (`http`, `webSocket`, `custom`)              |
| **Actions**    | Operations like `getBlockNumber`, `sendTransaction`           |
| **Chains**     | Chain configurations (`mainnet`, `sepolia`, `arbitrum`, etc.) |

## Constants

Viem exports useful constants for common values:

```typescript
import { maxUint256, maxUint128, maxInt256, zeroAddress, zeroHash } from "viem";

// Max values for uint types
maxUint256; // 2n ** 256n - 1n
maxUint128; // 2n ** 128n - 1n

// Zero values
zeroAddress; // 0x0000000000000000000000000000000000000000
zeroHash; // 0x0000000000000000000000000000000000000000000000000000000000000000
```

## Utilities

### Unit Conversion

Convert between wei and human-readable values:

```typescript
import { parseEther, formatEther, parseUnits, formatUnits } from "viem";

// ETH <-> Wei (18 decimals)
parseEther("1"); // 1000000000000000000n
formatEther(1000000000000000000n); // "1"

// Custom decimals (e.g., USDC with 6 decimals)
parseUnits("100", 6); // 100000000n
formatUnits(100000000n, 6); // "100"
```

### ABI Utilities

Parse human-readable ABIs:

```typescript
import { parseAbi, parseAbiItem } from "viem";

const abi = parseAbi([
  "function balanceOf(address owner) view returns (uint256)",
  "function transfer(address to, uint256 amount) returns (bool)",
  "event Transfer(address indexed from, address indexed to, uint256 amount)",
]);

const item = parseAbiItem("function name() view returns (string)");
```

### Address Utilities

```typescript
import { getAddress, isAddress, isAddressEqual } from "viem";

// Checksum address
getAddress("0xabc..."); // "0xAbc..." (checksummed)

// Validation
isAddress("0x..."); // true/false
isAddressEqual("0xAbc...", "0xabc..."); // true (case-insensitive)
```

## Clients

### Public Client (Read Operations)

For querying blockchain state:

```typescript
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(), // or http("https://eth-mainnet.g.alchemy.com/v2/...")
});

// Read operations
const blockNumber = await publicClient.getBlockNumber();
const balance = await publicClient.getBalance({ address: "0x..." });
const block = await publicClient.getBlock();
```

### Wallet Client (Write Operations)

For signing and sending transactions:

```typescript
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";

const account = privateKeyToAccount("0x...");

const walletClient = createWalletClient({
  account,
  chain: mainnet,
  transport: http(),
});

// Send transaction
const hash = await walletClient.sendTransaction({
  to: "0x...",
  value: parseEther("0.1"),
});
```

### Browser Wallet Client

For browser environments with injected wallets:

```typescript
import "viem/window";
import { createWalletClient, custom } from "viem";
import { mainnet } from "viem/chains";

const walletClient = createWalletClient({
  chain: mainnet,
  transport: custom(window.ethereum!),
});

// Request accounts
const [address] = await walletClient.requestAddresses();
```

### Extending Clients

Combine capabilities using `.extend()`:

```typescript
import { createWalletClient, http, publicActions } from "viem";
import { mainnet } from "viem/chains";

const client = createWalletClient({
  chain: mainnet,
  transport: http(),
}).extend(publicActions);

// Now supports both wallet and public actions
const balance = await client.getBalance({ address: "0x..." });
const hash = await client.sendTransaction({ to: "0x...", value: 1n });
```

## Contract Interactions

### Reading from Contracts

```typescript
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(),
});

const abi = [
  {
    inputs: [{ name: "owner", type: "address" }],
    name: "balanceOf",
    outputs: [{ name: "", type: "uint256" }],
    stateMutability: "view",
    type: "function",
  },
] as const;

const balance = await publicClient.readContract({
  address: "0x...", // Contract address
  abi,
  functionName: "balanceOf",
  args: ["0x..."], // Owner address
});
```

### Writing to Contracts

```typescript
const hash = await walletClient.writeContract({
  address: "0x...",
  abi,
  functionName: "transfer",
  args: ["0x...", parseUnits("100", 18)],
});
```

### Simulating Before Writing

Simulate a transaction before sending:

```typescript
const { request } = await publicClient.simulateContract({
  address: "0x...",
  abi,
  functionName: "transfer",
  args: ["0x...", parseUnits("100", 18)],
  account: "0x...",
});

const hash = await walletClient.writeContract(request);
```

## Account Types

### Local Accounts

For server-side or controlled environments:

```typescript
import { privateKeyToAccount, mnemonicToAccount } from "viem/accounts";

// From private key
const account = privateKeyToAccount("0x...");

// From mnemonic
const account = mnemonicToAccount("legal winner thank year wave sausage ...");
```

### JSON-RPC Accounts

For browser wallets:

```typescript
import "viem/window";

const [account] = await window.ethereum!.request({
  method: "eth_requestAccounts",
});
```

## Chain Configuration

### Built-in Chains

```typescript
import { mainnet, sepolia, arbitrum, optimism, polygon, base } from "viem/chains";

const client = createPublicClient({
  chain: arbitrum,
  transport: http(),
});
```

### Custom Chains

```typescript
import { defineChain } from "viem";

const customChain = defineChain({
  id: 123456,
  name: "My Chain",
  nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
  rpcUrls: {
    default: { http: ["https://rpc.mychain.com"] },
  },
  blockExplorers: {
    default: { name: "Explorer", url: "https://explorer.mychain.com" },
  },
});
```

## Documentation

This skill provides a reference for common operations. For comprehensive documentation, fetch the full viem docs using context7 MCP:

```
Library ID: /wevm/viem
```

Use context7 to query specific topics:

- `clients` - Client types and configuration
- `actions` - Available actions (read, write, wallet)
- `accounts` - Local and JSON-RPC accounts
- `contract` - Contract interactions (`readContract`, `writeContract`)
- `abi` - ABI encoding/decoding utilities
- `chains` - Supported chains and custom chain configuration

### Fetching Documentation

To fetch viem documentation for a specific topic:

1. Resolve the library ID with `mcp__context7__resolve-library-id` (or use `/wevm/viem` directly)
2. Call `mcp__context7__get-library-docs` with the topic parameter

Example topics: `"getting started"`, `"wallet client"`, `"send transaction"`, `"read contract"`.

