mcpField
V
viem-integration

viem-integration

github.com/uniswap開発2361.7k 回インストール2 日前に更新
リポジトリ

viem-integration について

TypeScript や JavaScript アプリケーションで viem を使い、EVM ブロックチェーンと連携するためのスキルです。クライアントやトランスポートの選択、チェーン上の読み書き、wagmi の利用方法を説明します。

主な機能

  1. 01PublicClient と WalletClient の設定
  2. 02HTTP、WebSocket、カスタムトランスポート
  3. 03チェーンとアカウントの管理
  4. 04コントラクトの読み取りと書き込み
  5. 05アドレス、単位、エラー処理のユーティリティ

活用シーン

  1. 01残高やコントラクトデータの読み取り
  2. 02トランザクション送信やメッセージ署名
  3. 03リアルタイムのブロックチェーンイベント監視
  4. 04React アプリへの EVM 接続追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/uniswap/uniswap-ai --skill viem-integration

インストール後、Claude Code で/viem-integrationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
accounts-and-keys.md
clients-and-transports.md
contract-patterns.md
reading-data.md
wagmi-react.md
writing-transactions.md

詳細

viem との統合

TypeScript/JavaScript アプリケーションで viem を使用して EVM ブロックチェーンを統合します。

クイック判断ガイド

構築するものこちらを使用
Node.js スクリプト/バックエンドviem と http トランスポート
React/Next.js フロントエンドwagmi フック(viem ベース)
リアルタイムイベントの監視viem と webSocket トランスポート
ブラウザーウォレットとの統合wagmi または viem のカスタムトランスポート

インストール

# Core library
npm install viem

# For React apps, also install wagmi
npm install wagmi viem @tanstack/react-query

基本概念

クライアント

viem では、2 種類のクライアントを使用します。

クライアント用途使用例
PublicClient読み取り専用操作残高の取得、コントラクトの読み取り、ログの取得
WalletClient書き込み操作トランザクションの送信、メッセージへの署名
トランスポート
トランスポート用途
http()標準的な RPC 呼び出し(最も一般的)
webSocket()リアルタイムイベントのサブスクリプション
custom()ブラウザーウォレット(window.ethereum)
チェーン

viem には 50 以上のチェーン定義が含まれています。viem/chains からインポートします。

import { mainnet, arbitrum, optimism, base, polygon } from 'viem/chains';

入力の検証ルール

ユーザー提供の値を生成された TypeScript コードに埋め込む前に、必ず以下を確認してください。

  • Ethereum アドレス:^0x[a-fA-F0-9]{40}$ に一致する必要があります。検証には viem の isAddress() を使用してください。
  • チェーン ID:viem がサポートするチェーン定義に含まれている必要があります。
  • 秘密鍵:ハードコードしてはいけません。必ず process.env.PRIVATE_KEY を使用し、実行時に検証してください。
  • RPC URL:https:// または wss:// プロトコルのみを使用してください。
  • ABI 入力:エンコードする前に、型が想定される Solidity の型と一致することを検証してください。

クイックスタートの例

残高の読み取り
import { createPublicClient, http, formatEther } from 'viem';
import { mainnet } from 'viem/chains';

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

const balance = await client.getBalance({
  address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
});

console.log(`Balance: ${formatEther(balance)} ETH`);
コントラクトの読み取り
import { createPublicClient, http, parseAbi } from 'viem';
import { mainnet } from 'viem/chains';

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

const abi = parseAbi([
  'function balanceOf(address) view returns (uint256)',
  'function decimals() view returns (uint8)',
]);

const balance = await client.readContract({
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
  abi,
  functionName: 'balanceOf',
  args: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'],
});
トランザクションの送信
import { createWalletClient, http, parseEther } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { mainnet } from 'viem/chains';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

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

const hash = await client.sendTransaction({
  to: '0x...',
  value: parseEther('0.1'),
});

console.log(`Transaction hash: ${hash}`);
コントラクトへの書き込み
import { createWalletClient, createPublicClient, http, parseAbi, parseUnits } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { mainnet } from 'viem/chains';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

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

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

const abi = parseAbi(['function transfer(address to, uint256 amount) returns (bool)']);

// Simulate first to catch errors
const { request } = await publicClient.simulateContract({
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  abi,
  functionName: 'transfer',
  args: ['0x...', parseUnits('100', 6)],
  account,
});

// Execute the transaction
const hash = await walletClient.writeContract(request);

// Wait for confirmation
const receipt = await publicClient.waitForTransactionReceipt({ hash });
console.log(`Confirmed in block ${receipt.blockNumber}`);

リファレンスドキュメント

各トピックの詳細については、以下を参照してください。

トピックリファレンスファイル
クライアントの設定、トランスポート、チェーンクライアントとトランスポート
ブロックチェーンデータの読み取りデータの読み取り
トランザクションの送信トランザクションの書き込み
秘密鍵、HD ウォレットアカウントと鍵
ABI の処理、マルチコールコントラクトのパターン
React/wagmi フックWagmi React

関連プラグイン

viem の基本に慣れたら、uniswap-trading プラグインを使って Uniswap スワップを包括的に統合できます。

  • Uniswap Trading API の統合
  • Universal Router SDK の使用
  • トークンスワップの実装

次のコマンドでインストールします:claude plugin add @uniswap/uniswap-trading


よく使うユーティリティ

単位変換
import { parseEther, formatEther, parseUnits, formatUnits } from 'viem';

// ETH
parseEther('1.5'); // 1500000000000000000n (wei)
formatEther(1500000000000000000n); // "1.5"

// Tokens (e.g., USDC with 6 decimals)
parseUnits('100', 6); // 100000000n
formatUnits(100000000n, 6); // "100"
アドレスユーティリティ
import { getAddress, isAddress } from 'viem';

isAddress('0x...'); // true/false
getAddress('0x...'); // checksummed address
ハッシュ化
import { keccak256, toHex } from 'viem';

keccak256(toHex('hello')); // 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8

エラー処理

viem は型付きエラーをスローするため、捕捉して処理できます。

import { ContractFunctionExecutionError, InsufficientFundsError } from 'viem'

try {
  await client.writeContract(...)
} catch (error) {
  if (error instanceof ContractFunctionExecutionError) {
    console.error('Contract call failed:', error.shortMessage)
  }
  if (error instanceof InsufficientFundsError) {
    console.error('Not enough ETH for gas')
  }
}

リソース

コメント