Integrate EVM blockchains using viem for TypeScript/JavaScript applications.
Works with
AI-first code editor with Composer
Before installing skills in Cursor, ensure your development environment meets these requirements:
node --versionviem-integrationExecute the skills CLI command in your project's root directory to begin installation:
Fetches viem-integration from uniswap/uniswap-ai and configures it for Cursor.
The CLI shows a list of agents. Use arrow keys and space to select Cursor:
Confirm successful installation by checking the skill directory location:
Restart Cursor to activate viem-integration. Access via /viem-integration in your agent's command palette.
We perform automated surface-level scans (Gen AI Scanner, Socket, Snyk) during installation. These checks detect common vulnerabilities but do not guarantee complete security. Always review skill source code and verify the publisher's reputation before production use.
Skills execute code in your environment. Always review source, verify the publisher, and test in isolation before production.
Submit your Claude Code skill and start earning
Create detailed user stories, acceptance criteria, and feature specs
Example
Generate user stories for 'password reset feature' with acceptance criteria, edge cases, and test scenarios
Reduce spec writing time by 50%, ensure comprehensive coverage
Research competitors, compare features, identify gaps
Example
Analyze 5 competitor products, create feature comparison matrix, suggest differentiation opportunities
Complete competitive research in 2 hours instead of 2 days
Evaluate features using frameworks (RICE, ICE, Kano) and create prioritized backlogs
Example
Score 20 feature ideas using RICE framework, generate prioritized roadmap with rationale
0
total installs
0
this week
198
GitHub stars
0
upvotes
Run in your terminal
0
installs
0
this week
198
stars
Integrate EVM blockchains using viem for TypeScript/JavaScript applications.
| 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 |
# Core library
npm install viem
# For React apps, also install wagmi
npm install wagmi viem @tanstack/react-query
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 |
| Transport | Use Case |
|---|---|
http() |
Standard RPC calls (most common) |
webSocket() |
Real-time event subscriptions |
custom() |
Browser wallets (window.ethereum) |
viem includes 50+ chain definitions. Import from viem/chains:
import { mainnet, arbitrum, optimism, base, polygon } from 'viem/chains';
Before interpolating ANY user-provided value into generated TypeScript code:
^0x[a-fA-F0-9]{40}$ — use viem's isAddress() for validationprocess.env.PRIVATE_KEY with runtime validationhttps:// or wss:// protocols onlyimport { 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}`);
For deeper coverage of specific topics: