viem by 0xsardius/onchain-typescript-skills
npx skills add https://github.com/0xsardius/onchain-typescript-skills --skill viem版本: Viem 2.x | 官方文档
Viem 是面向以太坊的现代 TypeScript 接口。此技能确保合约交互、客户端设置和类型安全的正确模式。
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
公共客户端(只读操作):
const publicClient = createPublicClient({
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})
钱包客户端(写入操作):
const account = privateKeyToAccount('0x...')
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})
始终对 ABI 使用 as const 以获得完整的类型推断:
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.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
Public Client (read-only operations):
const publicClient = createPublicClient({
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})
Wallet Client (write operations):
const account = privateKeyToAccount('0x...')
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'),
})
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// ✅ 正确 - 完全的类型安全
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`
const balance = await publicClient.readContract({
address: '0x...', // 合约地址
abi,
functionName: 'balanceOf',
args: ['0x...'], // 使用 `as const` 时,参数是完全类型化的
})
在写入前始终先模拟,以尽早捕获错误:
// 步骤 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 })
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()
const results = await publicClient.multicall({
contracts: [
{ address: '0x...', abi, functionName: 'balanceOf', args: ['0x...'] },
{ address: '0x...', abi, functionName: 'totalSupply' },
],
})
// results[0].result, results[1].result
| 错误 | 修复方法 |
|---|---|
ABI 缺少 as const | 添加 as const 以获得类型推断 |
对金额使用 Number | 使用 BigInt 字面量:1000000n |
| 未模拟直接写入 | 始终先使用 simulateContract |
| 硬编码 gas | 让 viem 估算,或使用 gas: await publicClient.estimateGas(...) |
| 未等待收据 | 使用 waitForTransactionReceipt 进行确认 |
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'] },
},
}
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/contract-patterns.md - 高级合约交互模式references/common-errors.md - 错误处理和调试指南每周安装次数
56
代码仓库
首次出现
2026年1月23日
安全审计
安装于
opencode47
gemini-cli44
codex43
cursor40
github-copilot38
claude-code36
Always use as const for ABIs to get full type inference:
// ✅ 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`
const balance = await publicClient.readContract({
address: '0x...', // Contract address
abi,
functionName: 'balanceOf',
args: ['0x...'], // Args are fully typed when using `as const`
})
Always simulate before writing to catch errors early:
// 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 })
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()
const results = await publicClient.multicall({
contracts: [
{ address: '0x...', abi, functionName: 'balanceOf', args: ['0x...'] },
{ address: '0x...', abi, functionName: 'totalSupply' },
],
})
// results[0].result, results[1].result
| Mistake | Fix |
|---|---|
Missing as const on ABI | Add as const for type inference |
Using Number for amounts | Use BigInt literals: 1000000n |
| Writing without simulate | Always simulateContract first |
| Hardcoding gas | Let viem estimate, or use gas: await publicClient.estimateGas(...) |
| Not awaiting receipts | Use waitForTransactionReceipt for confirmation |
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'] },
},
}
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
}
}
}
For detailed patterns, see:
references/contract-patterns.md - Advanced contract interaction patternsreferences/common-errors.md - Error handling and debugging guideWeekly Installs
56
Repository
First Seen
Jan 23, 2026
Security Audits
Installed on
opencode47
gemini-cli44
codex43
cursor40
github-copilot38
claude-code36
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
122,000 周安装