viem
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseViem Skill
Viem 技能指南
Version: Viem 2.x | Official Docs
Viem is the modern TypeScript interface for Ethereum. This skill ensures correct patterns for contract interactions, client setup, and type safety.
版本: Viem 2.x | 官方文档
Viem 是面向Ethereum的现代化TypeScript接口。本技能指南确保你掌握合约交互、客户端配置和类型安全的正确实践。
Quick Reference
快速参考
typescript
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'typescript
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'Critical Patterns
核心实践模式
1. Client Setup
1. 客户端配置
Public Client (read-only operations):
typescript
const publicClient = createPublicClient({
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})Wallet Client (write operations):
typescript
const account = privateKeyToAccount('0x...')
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})公共客户端(只读操作):
typescript
const publicClient = createPublicClient({
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})钱包客户端(写入操作):
typescript
const account = privateKeyToAccount('0x...')
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})2. ABI Type Safety (CRITICAL)
2. ABI 类型安全(至关重要)
Always use for ABIs to get full type inference:
as consttypescript
// ✅ CORRECT - Full type safety
const abi = [
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'owner', type: 'address' }],
outputs: [{ name: '', type: 'uint256' }],
},
] as const
// ❌ WRONG - No type inference
const abi = [{ name: 'balanceOf', ... }] // Missing `as const`始终为ABI添加以获得完整的类型推断:
as consttypescript
// ✅ 正确做法 - 完整类型安全
const abi = [
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'owner', type: 'address' }],
outputs: [{ name: '', type: 'uint256' }],
},
] as const
// ❌ 错误做法 - 无类型推断
const abi = [{ name: 'balanceOf', ... }] // 缺少`as const`3. Contract Read Pattern
3. 合约读取模式
typescript
const balance = await publicClient.readContract({
address: '0x...', // Contract address
abi,
functionName: 'balanceOf',
args: ['0x...'], // Args are fully typed when using `as const`
})typescript
const balance = await publicClient.readContract({
address: '0x...', // 合约地址
abi,
functionName: 'balanceOf',
args: ['0x...'], // 当使用`as const`时,参数会被完全类型化
})4. Contract Write Pattern (Simulate First!)
4. 合约写入模式(先模拟!)
Always simulate before writing to catch errors early:
typescript
// Step 1: Simulate
const { request } = await publicClient.simulateContract({
account,
address: '0x...',
abi,
functionName: 'transfer',
args: ['0x...', 1000000n], // Use BigInt for uint256
})
// Step 2: Execute
const hash = await walletClient.writeContract(request)
// Step 3: Wait for receipt
const receipt = await publicClient.waitForTransactionReceipt({ hash })写入前务必先模拟,以便提前捕获错误:
typescript
// 步骤1:模拟
const { request } = await publicClient.simulateContract({
account,
address: '0x...',
abi,
functionName: 'transfer',
args: ['0x...', 1000000n], // 对uint256类型使用BigInt
})
// 步骤2:执行
const hash = await walletClient.writeContract(request)
// 步骤3:等待交易回执
const receipt = await publicClient.waitForTransactionReceipt({ hash })5. Event Watching
5. 事件监听
typescript
const unwatch = publicClient.watchContractEvent({
address: '0x...',
abi,
eventName: 'Transfer',
onLogs: (logs) => {
for (const log of logs) {
console.log(log.args.from, log.args.to, log.args.value)
}
},
})
// Clean up
unwatch()typescript
const unwatch = publicClient.watchContractEvent({
address: '0x...',
abi,
eventName: 'Transfer',
onLogs: (logs) => {
for (const log of logs) {
console.log(log.args.from, log.args.to, log.args.value)
}
},
})
// 清理资源
unwatch()6. Multicall for Batch Reads
6. 批量读取的Multicall用法
typescript
const results = await publicClient.multicall({
contracts: [
{ address: '0x...', abi, functionName: 'balanceOf', args: ['0x...'] },
{ address: '0x...', abi, functionName: 'totalSupply' },
],
})
// results[0].result, results[1].resulttypescript
const results = await publicClient.multicall({
contracts: [
{ address: '0x...', abi, functionName: 'balanceOf', args: ['0x...'] },
{ address: '0x...', abi, functionName: 'totalSupply' },
],
})
// results[0].result, results[1].resultCommon Mistakes
常见错误
| Mistake | Fix |
|---|---|
Missing | Add |
Using | Use |
| Writing without simulate | Always |
| Hardcoding gas | Let viem estimate, or use |
| Not awaiting receipts | Use |
| 错误 | 修复方案 |
|---|---|
ABI未添加 | 添加 |
使用 | 使用 |
| 未模拟直接写入 | 始终先执行 |
| 硬编码gas值 | 让viem自动估算,或使用 |
| 未等待交易回执 | 使用 |
Chain Configuration
链配置
typescript
import { mainnet, polygon, arbitrum, optimism, base } from 'viem/chains'
// Custom chain
const customChain = {
id: 123,
name: 'My Chain',
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
rpcUrls: {
default: { http: ['https://rpc.mychain.com'] },
},
}typescript
import { mainnet, polygon, arbitrum, optimism, base } from 'viem/chains'
// 自定义链
const customChain = {
id: 123,
name: 'My Chain',
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
rpcUrls: {
default: { http: ['https://rpc.mychain.com'] },
},
}Error Handling
错误处理
typescript
import { BaseError, ContractFunctionRevertedError } from 'viem'
try {
await publicClient.simulateContract({ ... })
} catch (err) {
if (err instanceof BaseError) {
const revertError = err.walk(e => e instanceof ContractFunctionRevertedError)
if (revertError instanceof ContractFunctionRevertedError) {
const errorName = revertError.data?.errorName
// Handle specific revert reason
}
}
}typescript
import { BaseError, ContractFunctionRevertedError } from 'viem'
try {
await publicClient.simulateContract({ ... })
} catch (err) {
if (err instanceof BaseError) {
const revertError = err.walk(e => e instanceof ContractFunctionRevertedError)
if (revertError instanceof ContractFunctionRevertedError) {
const errorName = revertError.data?.errorName
// 处理具体的回滚原因
}
}
}References
参考资料
For detailed patterns, see:
- - Advanced contract interaction patterns
references/contract-patterns.md - - Error handling and debugging guide
references/common-errors.md - Viem Documentation - Official docs
- Viem GitHub - Source and releases
如需了解详细模式,请查阅:
- - 高级合约交互模式
references/contract-patterns.md - - 错误处理与调试指南
references/common-errors.md - Viem官方文档
- Viem GitHub仓库 - 源码与版本发布信息