mcpField
V
viem

viem

github.com/0xsardius开发0186 次安装41 周前更新
代码仓库

关于 viem

面向使用 Viem 2.x 构建 Ethereum 交互型 TypeScript 应用的开发者技能,涵盖类型安全的客户端设置、合约读写、事件监听及常见错误预防方法。

主要功能

  1. 01公共与钱包客户端设置
  2. 02类型安全的 ABI 写法
  3. 03合约读取与模拟写入
  4. 04合约事件监听
  5. 05Multicall 批量读取
  6. 06错误处理与链配置

适用场景

  1. 01设置只读或钱包客户端
  2. 02读取和写入智能合约
  3. 03监听合约事件
  4. 04批量执行合约读取

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/0xsardius/onchain-typescript-skills --skill viem

安装后在 Claude Code 中输入/viem确认已加载。

附带文件references/common-errors.mdreferences/contract-patterns.md

详细介绍

Viem 技能

版本: Viem 2.x | 官方文档

Viem 是面向 Ethereum 的现代 TypeScript 接口。此技能确保合约交互、客户端设置和类型安全使用正确模式。

快速参考

import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'

关键模式

1. 客户端设置

公共客户端(只读操作):

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'),
})
2. ABI 类型安全(重要)

始终为 ABI 使用 as const,以获得完整的类型推断:

// ✅ 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`
3. 合约读取模式
const balance = await publicClient.readContract({
  address: '0x...', // Contract address
  abi,
  functionName: 'balanceOf',
  args: ['0x...'], // Args are fully typed when using `as const`
})
4. 合约写入模式(先模拟!)

写入前始终先进行模拟,以便尽早发现错误:

// 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 })
5. 事件监听
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()
6. 使用 Multicall 批量读取
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'

// 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
    }
  }
}

参考资料

如需了解详细模式,请参阅:

  • references/contract-patterns.md - 高级合约交互模式
  • references/common-errors.md - 错误处理与调试指南
  • Viem 文档 - 官方文档
  • Viem GitHub - 源代码与版本发布

评论

支持 Markdown