skills/uniswap/uniswap-ai/viem-integration

viem-integration

SKILL.md

viem Integration

Integrate EVM blockchains using viem for TypeScript/JavaScript applications.

Quick Decision Guide

Building... Use This
Node.js script/backend viem with http transport
React/Next.js frontend wagmi hooks (built on viem)
Real-time event monitoring viem with webSocket transport
Browser wallet integration wagmi or viem custom transport

Installation

# Core library
npm install viem

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

Core Concepts

Clients

viem uses two client types:

Client Purpose Example Use
PublicClient Read-only operations Get balances, read contracts, fetch logs
WalletClient Write operations Send transactions, sign messages

Transports

Transport Use Case
http() Standard RPC calls (most common)
webSocket() Real-time event subscriptions
custom() Browser wallets (window.ethereum)

Chains

viem includes 50+ chain definitions. Import from viem/chains:

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

Input Validation Rules

Before interpolating ANY user-provided value into generated TypeScript code:

  • Ethereum addresses: MUST match ^0x[a-fA-F0-9]{40}$ — use viem's isAddress() for validation
  • Chain IDs: MUST be from viem's supported chain definitions
  • Private keys: MUST NEVER be hardcoded — always use process.env.PRIVATE_KEY with runtime validation
  • RPC URLs: MUST use https:// or wss:// protocols only
  • ABI inputs: Validate types match expected Solidity types before encoding

Quick Start Examples

Read Balance

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`);

Read Contract

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'],
});

Send Transaction

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}`);

Write to Contract

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}`);

Reference Documentation

For deeper coverage of specific topics:

Topic Reference File
Client setup, transports, chains Clients & Transports
Reading blockchain data Reading Data
Sending transactions Writing Transactions
Private keys, HD wallets Accounts & Keys
ABI handling, multicall Contract Patterns
React/wagmi hooks Wagmi React

Related Plugins

Once you're comfortable with viem basics, the uniswap-trading plugin provides comprehensive Uniswap swap integration:

  • Uniswap Trading API integration
  • Universal Router SDK usage
  • Token swap implementations

Install it with: claude plugin add @uniswap/uniswap-trading


Common Utilities

Unit Conversion

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"

Address Utilities

import { getAddress, isAddress } from 'viem';

isAddress('0x...'); // true/false
getAddress('0x...'); // checksummed address

Hashing

import { keccak256, toHex } from 'viem';

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

Error Handling

viem throws typed errors that can be caught and handled:

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')
  }
}

Resources

Weekly Installs
263
GitHub Stars
174
First Seen
Feb 12, 2026
Installed on
codex249
opencode248
gemini-cli243
github-copilot241
cursor239
kimi-cli238