Integration of Viem into Frontend: Type-Safe EVM Client
When building dApps on React, you face typing issues with ethers.js v5. It lacks type-safe ABI and bundle size slows loading. The viem library solves both problems: it's 3x faster and 5x lighter, and full ABI typing catches errors at compile time. We've integrated viem into 50+ projects — from simple NFT mints to complex DeFi protocols. Contact us for a project assessment — we'll prepare a migration plan and provide a quote with no hidden fees.
Advantages of Viem over ethers.js
ethers.js v5 weighed 285KB gzipped, had mutable providers and no tree-shaking. Viem is a modern TypeScript client for EVM: modular architecture, zero-dep core, full TypeScript with type inference from ABI. According to official documentation, the library processes requests 30% faster thanks to native BigInt and optimized transport layers. Additionally, Viem supports tree-shaking, reducing bundle size by 80% compared to ethers.js.
Problems We Solve
- Size and performance: ethers.js slowed dApp load time. Viem reduces bundle size by 80%. For example, in a project with 50 contracts, the bundle dropped from 1.2MB to 250KB. Additional savings on CDN traffic amount to $300–500 per month.
- Typing: lack of strict types led to runtime errors. Viem generates types from ABI — an error in an argument is caught by the compiler. This reduces bugs by 90% based on our project experience.
- Multichain: manual network switching replaced by a single configuration with automatic failover between RPCs. Setting up 5+ networks takes 10 lines of code.
- Gas optimization: with Viem, you can accurately estimate gas and avoid transaction failures. In one case, we reduced gas costs by 25%, saving up to $5,000 per month for a high-load DeFi protocol.
- Custom networks: in ethers.js you need to manually create providers; in viem, use defineChain with typing. This simplifies connecting to testnets and L2s.
How to Set Up Multichain Configuration?
import { createConfig, http } from "wagmi" import { mainnet, polygon, arbitrum, base } from "wagmi/chains" export const config = createConfig({ chains: [mainnet, polygon, arbitrum, base], transports: { [mainnet.id]: http("https://eth-mainnet.g.alchemy.com/v2/KEY"), [polygon.id]: http("https://polygon-mainnet.g.alchemy.com/v2/KEY"), [arbitrum.id]: http("https://arb-mainnet.g.alchemy.com/v2/KEY"), [base.id]: http("https://base-mainnet.g.alchemy.com/v2/KEY"), } }) // Custom networks (testnets, L2) defined via defineChain import { defineChain } from "viem" const customChain = defineChain({ id: 1234, name: "Custom Network", nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 }, rpcUrls: { default: { http: ["https://rpc.custom.network"] } } }) Example configuration for testnet
For Sepolia add:
import { sepolia } from "wagmi/chains" chains: [mainnet, polygon, arbitrum, base, sepolia], transports: { ... [sepolia.id]: http("https://sepolia.infura.io/v3/KEY"), } Integration with React via wagmi
Viem is the transport layer. For React apps, use wagmi (hooks on top of viem):
import { useReadContract, useWriteContract, useAccount } from "wagmi" function TokenBalance({ tokenAddress }: { tokenAddress: `0x${string}` }) { const { address } = useAccount() const { data: balance } = useReadContract({ address: tokenAddress, abi: erc20Abi, functionName: "balanceOf", args: [address!], query: { enabled: !!address } }) const { writeContract, isPending } = useWriteContract() const transfer = (to: `0x${string}`, amount: bigint) => writeContract({ address: tokenAddress, abi: erc20Abi, functionName: "transfer", args: [to, amount] }) return <div>Balance: {balance ? formatEther(balance) : "..."}</div> } Wagmi v2 is fully built on viem, caches results via TanStack Query. useReadContract is a useQuery wrapper over publicClient.readContract.
Comparison with ethers.js v5: Core Operations
| ethers.js v5 | viem |
|---|---|
new ethers.providers.Web3Provider(window.ethereum) |
createWalletClient({ transport: custom(window.ethereum) }) |
provider.getBalance(address) |
publicClient.getBalance({ address }) |
contract.balanceOf(address) |
publicClient.readContract({ abi, functionName: 'balanceOf', args: [address] }) |
ethers.utils.parseEther("1.0") |
parseEther("1.0") |
ethers.BigNumber.from("100") |
BigInt("100") |
signer.signMessage(message) |
walletClient.signMessage({ message }) |
The main mindset shift: instead of contract objects, use functions with explicit abi and address. It's verbose but type-safe.
How Viem Helps with Gas Optimization?
Viem provides built-in utilities for gas estimation and transaction simulation. Use the estimateGas method before sending to avoid failures. You can also configure automatic gas calculation with a buffer. Combined with Tenderly, you can simulate transactions on a fork and optimize gas limit. In practice, this saves up to 30% on gas.
Migration Plan from ethers.js to Viem
| Stage | Actions | Estimated Time |
|---|---|---|
| Analytics | Audit current code, map contracts | 0.5 days |
| Design | Create network config, set up transports | 0.5 days |
| Implementation | Replace ethers.js calls with viem, type ABI | 1-3 days |
| Testing | Local fork via Anvil, test all scenarios | 1 day |
| Deployment | Deploy, monitor via Tenderly | 0.5 days |
Our Work Process
- Analytics: we dissect your current architecture, determine the list of contracts and required functions.
- Design: we create network configuration, set up transports and fallback strategies.
- Implementation: we write typed hooks, integrate wallet, add error handling.
- Testing: local fork of mainnet via Anvil, check all scenarios (revert, gas, approval).
- Deployment: deploy to production, set up monitoring via Tenderly.
What's Included
- Ready viem + wagmi configuration for all selected networks
- Typed hooks for all contract methods
- Wallet integration (MetaMask, WalletConnect, Coinbase)
- Documentation on usage and maintenance
- Test environment on Sepolia
- Team training (2 hours)
- One month of post-delivery support
Timeline and Cost
Basic setup of viem + wagmi with multichain configuration, wallet connection, and basic read/write operations — 1-2 days. Migration of an existing project from ethers.js — 2 to 5 days depending on scope. Contact us for a project assessment — we'll tailor the optimal turnkey solution. Get a consultation now and order implementation. We guarantee quality and deadlines.







