Skip to content

Ethers v5 → viem Migration Guide

Migrate from Ethers v5 to viem

This is a long document. Feel free to use the search bar above (⌘ K) or the Table of Contents to the side. If there is an API you need which is missing or cannot find, create a Parity Request here.

You may notice some of the APIs in viem are a little more verbose than Ethers. We prefer boring code and we want to strongly embrace clarity & composability. We believe that verbose APIs are more flexible to move, change and remove compared to code that is prematurely abstracted and hard to change.

Provider → Client

getDefaultProvider

Ethers

import { getDefaultProvider } from 'ethers'
 
const provider = getDefaultProvider() 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: http() 
}) 

We are more verbose here – we want to be explicit and clear what chain you are connecting to & what transport you are using to avoid any confusion. :)

JsonRpcProvider

Ethers

This is also interchangeable with StaticJsonRpcProvider.

import { providers } from 'ethers'
 
const provider = new providers.JsonRpcProvider('https://cloudflare-eth.com') 

Custom Chain:

import { providers } from 'ethers'
 
const provider = new providers.JsonRpcProvider('https://rpc.ankr.com/fantom/​', { 
  name: 'Fantom', 
  id: 250
}) 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: http('https://cloudflare-eth.com') 
}) 

Custom Chain:

import { createPublicClient, http } from 'viem'
import { fantom } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: fantom, 
  transport: http('https://rpc.ankr.com/fantom/​') 
}) 

viem exports custom EVM chains in the viem/chains entrypoint.

InfuraProvider

Ethers

import { providers } from 'ethers'
 
const provider = new providers.InfuraProvider('homestead', '<apiKey>') 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: http('https://mainnet.infura.io/v3/<apiKey>') 
}) 

viem does not have custom API Provider clients – you can just pass in their RPC URL.

AlchemyProvider

Ethers

import { providers } from 'ethers'
 
const provider = new providers.AlchemyProvider('homestead', '<apiKey>') 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: http('https://eth-mainnet.g.alchemy.com/v2/<apiKey>') 
}) 

viem does not have custom API Provider clients – you can just pass in their RPC URL.

CloudflareProvider

Ethers

import { providers } from 'ethers'
 
const provider = new providers.CloudflareProvider() 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: http('https://cloudflare-eth.com/') 
}) 

viem does not have custom API Provider clients – you can just pass in their RPC URL.

PocketProvider

Ethers

import { providers } from 'ethers'
 
const provider = new providers.PocketProvider('homestead', '<apiKey>') 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: http('https://eth-mainnet.gateway.pokt.network/v1/lb/<apiKey>') 
}) 

viem does not have custom API Provider clients – you can just pass in their RPC URL.

AnkrProvider

Ethers

import { providers } from 'ethers'
 
const provider = new providers.AnkrProvider('homestead', '<apiKey>') 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: http('https://rpc.ankr.com/eth/<apiKey>') 
}) 

viem does not have custom API Provider clients – you can just pass in their RPC URL.

FallbackProvider

Ethers

import { providers } from 'ethers'
 
const alchemy = new providers.AlchemyProvider('homestead', '<apiKey>') 
const infura = new providers.InfuraProvider('homestead', '<apiKey>') 
const provider = new providers.FallbackProvider([alchemy, infura]) 

viem

import { createPublicClient, http, fallback } from 'viem'
import { mainnet } from 'viem/chains'
 
const alchemy = http('https://eth-mainnet.g.alchemy.com/v2/<apiKey>') 
const infura = http('https://mainnet.infura.io/v3/<apiKey>') 
 
const client = createPublicClient({
  chain: mainnet,
  transport: fallback([alchemy, infura]) 
})

IpcProvider

Coming soon.

JsonRpcBatchProvider

Coming soon.

Web3Provider

Ethers

import { providers } from 'ethers'
 
const provider = new providers.Web3Provider(window.ethereum) 

viem

import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createWalletClient({ 
  chain: mainnet, 
  transport: custom(window.ethereum) 
}) 

WebSocketProvider

Ethers

import { providers } from 'ethers'
 
const provider = new providers.WebSocketProvider('wss://eth-mainnet.g.alchemy.com/v2/<apiKey>') 

viem

import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({ 
  chain: mainnet, 
  transport: webSocket('wss://eth-mainnet.g.alchemy.com/v2/<apiKey>') 
}) 

Signers → Accounts

JsonRpcSigner

Ethers

import { providers } from 'ethers'
 
const provider = new providers.Web3Provider(window.ethereum)
 
const [address] = await provider.listAccounts() 
const signer = provider.getSigner(address) 
 
signer.sendTransaction({ ... })

viem

import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
 
const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' }) 
 
const client = createWalletClient({
  account, 
  chain: mainnet,
  transport: custom(window.ethereum)
})
 
client.sendTransaction({ ... })

viem uses the term "Account" rather than "Signer".

Wallet

Ethers

import { providers, Wallet } from 'ethers'
 
const provider = new providers.Web3Provider(window.ethereum)
 
const wallet = new Wallet('0x...', provider) 
 
wallet.sendTransaction({ ... })

viem

import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
 
const account = privateKeyToAccount('0x...') 
 
const client = createWalletClient({
  account, 
  chain: mainnet,
  transport: custom(window.ethereum)
})
 
client.sendTransaction({ ... })

viem uses the term "Account" rather than "Signer".

Provider Methods

Ethers

import { getDefaultProvider } from 'ethers'
 
const provider = getDefaultProvider()
 
provider.getBlock(...) 
provider.getTransaction(...) 
...

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createPublicClient({
  chain: mainnet,
  transport: http()
})
 
client.getBlock(...) 
client.getTransaction(...) 
...

Methods that extend off the Public Client are Public Actions. Read more.

There are API differences in all of these methods. Use the search bar at the top of the page to learn more about them.

Signer Methods

JsonRpcSigner

Ethers

import { providers } from 'ethers'
 
const provider = new providers.Web3Provider(window.ethereum)
 
const [address] = await provider.listAccounts()
const signer = provider.getSigner(address)
 
signer.sendTransaction(...) 
signer.signMessage(...) 
...

viem

import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
 
const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' })
 
const client = createWalletClient({
  account,
  chain: mainnet,
  transport: custom(window.ethereum)
})
 
client.sendTransaction({ ... }) 
client.signMessage({ ... }) 
...

Methods that extend off the Wallet Client are Wallet Actions. Read more.

There are API differences in all of these methods. Use the search bar at the top of the page to learn more about them.

Contract Interaction

Reading from Contracts

Ethers

import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
 
const provider = getDefaultProvider()
 
const { abi, address } = wagmiContractConfig 
const contract = new Contract(address, abi, provider) 
const supply = await contract.totalSupply() 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
 
const client = createPublicClient({
  chain: mainnet,
  transport: http()
})
 
const supply = await client.readContract({ 
  ...wagmiContractConfig, 
  functionName: 'totalSupply'
}) 

Writing to Contracts

Ethers

import { Contract, providers } from 'ethers'
import { wagmiContractConfig } from './abi'
 
const provider = new providers.Web3Provider(window.ethereum)
 
const [address] = await provider.listAccounts()
const signer = provider.getSigner(address)
 
const { abi, address } = wagmiContractConfig 
const contract = new Contract(address, abi, signer) 
const hash = await contract.mint() 

viem

import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
 
const walletClient = createWalletClient({
  chain: mainnet,
  transport: custom(window.ethereum)
})
 
const [address] = await walletClient.getAddresses()
 
const hash = await walletClient.writeContract({ 
  ...wagmiContractConfig, 
  functionName: 'mint', 
  account: address, 
}) 

Deploying Contracts

Ethers

import { ContractFactory, providers } from 'ethers'
import { abi, bytecode } from './abi'
 
const provider = new providers.Web3Provider(window.ethereum)
 
const [address] = await provider.listAccounts()
const signer = provider.getSigner(address)
 
const contract = new ContractFactory(abi, bytecode, signer) 
await contract.deploy() 

viem

import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { abi, bytecode } from './abi'
 
const walletClient = createWalletClient({
  chain: mainnet,
  transport: custom(window.ethereum)
})
 
const [address] = await walletClient.getAddresses()
 
await walletClient.deployContract({ 
  abi, 
  account: address, 
  bytecode, 
}) 

Contract Events

Ethers

import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
 
const provider = getDefaultProvider()
 
const { abi, address } = wagmiContractConfig 
const contract = new Contract(address, abi, provider) 
 
const listener = (from, to, amount, event) => { 
  // ...
} 
contract.on('Transfer', listener) 
 
// unsubscribe
contract.off('Transfer', listener) 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
 
const client = createPublicClient({
  chain: mainnet,
  transport: http()
})
 
const unwatch = client.watchContractEvent({ 
  ...wagmiContractConfig, 
  eventName: 'Transfer', 
  onLogs: logs => { 
    const { args: { from, to, amount }, eventName } = logs[0] 
    // ...
  }, 
}) 
 
// unsubscribe
unwatch() 

Note: Logs are batched between polling intervals in viem to avoid excessive callback invocations. You can disable this behavior with batch: false however.

Gas Estimation

Ethers

import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
 
const provider = getDefaultProvider()
 
const { abi, address } = wagmiContractConfig 
const contract = new Contract(address, abi, provider) 
const gas = await contract.estimateGas.mint() 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
 
const client = createPublicClient({
  chain: mainnet,
  transport: http()
})
 
const gas = await client.estimateContractGas({ 
  ...wagmiContractConfig,  
  functionName: 'mint'
}) 

Call

Ethers

import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
 
const provider = getDefaultProvider()
 
const { abi, address } = wagmiContractConfig 
const contract = new Contract(address, abi, provider) 
await contract.callStatic.mint() 

viem

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
 
const client = createPublicClient({
  chain: mainnet,
  transport: http()
})
 
await client.simulateContract({ 
  ...wagmiContractConfig,  
  functionName: 'mint'
}) 

Contract Instances

Ethers

import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
 
const provider = getDefaultProvider()
 
const { abi, address } = wagmiContractConfig 
const contract = new Contract(address, abi, provider) 
 
const supply = await contract.totalSupply()
const listener = (from, to, amount, event) => {
  // ...
}
contract.on('Transfer', listener)
contract.off('Transfer', listener)

viem

import { createPublicClient, http, getContract } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
 
const client = createPublicClient({
  chain: mainnet,
  transport: http()
})
 
const contract = getContract({ 
  ...wagmiContractConfig, 
  client, 
}) 
 
const supply = await contract.read.totalSupply()
const unwatch = contract.watchEvent.Transfer({
  onLogs: logs => {
    const { args: { from, to, amount }, eventName } = logs[0]
    // ...
  },
})
unwatch()

ABI Utilities

abiCoder.encode

Ethers

import { utils } from 'ethers'
 
const abiCoder = utils.defaultAbiCoder()
 
// Object
abiCoder.encode(
  [{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
  [1234, 'Hello world']
)
 
// Human Readable
abiCoder.encode(
  ['uint', 'string'], 
  [1234, 'Hello World']
);

viem

import { encodeAbiParameters, parseAbiParameters } from 'viem'
 
// Object
encodeAbiParameters(
  [{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
  [1234, 'Hello world']
)
 
// Human Readable
encodeAbiParameters(
  parseAbiParameters('uint, string'),
  [1234, 'Hello world']
)

abiCoder.decode

Ethers

import { utils } from 'ethers'
 
const abiCoder = utils.defaultAbiCoder()
 
// Object
abiCoder.decode(
  [{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
  '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)
 
// Human Readable
abiCoder.decode(
  ['uint', 'string'], 
  '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
);

viem

import { decodeAbiParameters, parseAbiParameters } from 'viem'
 
// Object
decodeAbiParameters(
  [{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
  '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)
 
// Human Readable
decodeAbiParameters(
  parseAbiParameters('uint, string'),
  '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)

Notice: different from ethers, viem only supports standard tuple expression for Human Readable. example: (uint a, string b) is valid, but tuple(uint a, string b) is not.

Fragments & Interfaces

In viem, there is no concept of "fragments" & "interfaces". We want to stick as close to the wire as possible and not introduce middleware abstractions and extra layers over ABIs. Instead of working with "fragments", we encourage you to work with the ABI itself. We provide utilities such as getAbiItem, parseAbi parseAbiItem, parseAbiParameters and parseAbiParameter which covers the use cases of interfaces & fragments.

Interface.format

viem only supports Human Readable → Object format.

Ethers

import { utils } from 'ethers'
 
const interface = new Interface([ 
  'constructor(string symbol, string name)', 
  'function transferFrom(address from, address to, uint amount)', 
  'function transferFrom(address from, address to, uint amount, bool x)', 
  'function mint(uint amount) payable', 
  'function balanceOf(address owner) view returns (uint)'
]) 
const json = interface.format(utils.FormatTypes.json) 

viem

import { parseAbi } from 'viem'
 
const json = parseAbi([ 
  'constructor(string symbol, string name)', 
  'function transferFrom(address from, address to, uint amount)', 
  'function transferFrom(address from, address to, uint amount, bool x)', 
  'function mint(uint amount) payable', 
  'function balanceOf(address owner) view returns (uint)', 
  'event Transfer(address indexed from, address indexed to, uint256 amount)'
]) 

Fragment.from

ethers

import { utils } from 'ethers'
 
const fragment = utils.Fragment.from('function balanceOf(address owner) view returns (uint)') 

viem

import { parseAbiItem } from 'viem'
 
const abiItem = parseAbiItem('function balanceOf(address owner) view returns (uint)') 

ParamType.from

ethers

import { utils } from 'ethers'
 
const param = utils.ParamType.from('address owner') 

viem

import { parseAbiParameter } from 'viem'
 
const param = parseAbiParameter('address owner') 

Fragment Access

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const interface = new utils.Interface(abi)  
interface.getFunction('transferFrom') 
interface.getEvent('Transfer') 

viem

import { getAbiItem } from 'viem'
import { abi } from './abi'
 
getAbiItem({ abi, name: 'transferFrom' })  
getAbiItem({ abi, name: 'Transfer' }) 

Interface.encodeDeploy

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi);  
const data = iface.encodeDeploy(['SYM', 'Some Name']) 

viem

import { encodeDeployData } from 'viem'
import { abi, bytecode } from './abi'
 
const data = encodeDeployData({ 
  abi, 
  bytecode, 
  args: ['SYM', 'Some Name'] 
}) 

Note: viem concatinates the contract bytecode onto the ABI encoded data.

Interface.encodeErrorResult

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi);  
const data = iface.encodeErrorResult('AccountLocked', [ 
  '0x8ba1f109551bD432803012645Ac136ddd64DBA72', 
  utils.parseEther('1.0') 
]); 

viem

import { encodeErrorResult, parseEther } from 'viem'
import { abi } from './abi'
 
const data = encodeErrorResult({  
  abi: wagmiAbi, 
  errorName: 'AccountLocked', 
  args: [ 
    '0x8ba1f109551bD432803012645Ac136ddd64DBA72', 
    parseEther('1.0') 
  ] 
}) 

Interface.encodeFilterTopics

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi);  
const data = iface.encodeFilterTopics('Transfer', [ 
  null, 
  '0x8ba1f109551bD432803012645Ac136ddd64DBA72'
]) 

viem

import { encodeEventTopics } from 'viem'
import { abi } from './abi'
 
const data = encodeEventTopics({ 
  abi, 
  eventName: 'Transfer', 
  args: { 
    to: '0x8ba1f109551bD432803012645Ac136ddd64DBA72'
  } 
}) 

Interface.encodeFunctionData

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi); 
const data = iface.encodeFunctionData('transferFrom', [ 
  '0x8ba1f109551bD432803012645Ac136ddd64DBA72', 
  '0xaB7C8803962c0f2F5BBBe3FA8bf41cd82AA1923C', 
  parseEther('1.0') 
]) 

viem

import { encodeFunctionData, parseEther } from 'viem'
import { abi } from './abi'
 
const data = encodeFunctionData({  
  abi, 
  functionName: 'transferFrom', 
  args: [ 
    '0x8ba1f109551bD432803012645Ac136ddd64DBA72', 
    '0xaB7C8803962c0f2F5BBBe3FA8bf41cd82AA1923C', 
    parseEther('1.0') 
  ] 
}) 

Interface.encodeFunctionResult

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi); 
const data = iface.encodeFunctionResult('balanceOf', [ 
  '0x8ba1f109551bD432803012645Ac136ddd64DBA72'
]) 

viem

import { encodeFunctionResult, parseEther } from 'viem'
import { abi } from './abi'
 
const data = encodeFunctionResult({  
  abi, 
  functionName: 'balanceOf', 
  value: ['0x8ba1f109551bD432803012645Ac136ddd64DBA72'] 
}) 

Interface.decodeErrorResult

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi); 
const result = iface.decodeErrorResult("AccountLocked", '0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000') 

viem

import { decodeErrorResult, parseEther } from 'viem'
import { abi } from './abi'
 
const result = decodeErrorResult({  
  abi, 
  data: '0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000'
}) 

Interface.decodeEventLog

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi); 
const result = iface.decodeEventLog( 
  'Transfer', 
  data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', 
  topics: [ 
    '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', 
    '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72', 
    '0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c'
  ] 
); 

viem

import { decodeEventLog, parseEther } from 'viem'
import { abi } from './abi'
 
const result = decodeEventLog({ 
  abi, 
  data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', 
  topics: [ 
    '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', 
    '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72', 
    '0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c'
  ] 
}) 

Interface.decodeFunctionData

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi); 
const result = iface.decodeFunctionData('transferFrom', '0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000'); 

viem

import { decodeFunctionData, parseEther } from 'viem'
import { abi } from './abi'
 
const result = decodeFunctionData({ 
  abi, 
  data: '0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000', 
}) 

Interface.decodeFunctionResult

Ethers

import { utils } from 'ethers'
import { abi } from './abi'
 
const iface = new utils.Interface(abi); 
const result = iface.decodeFunctionResult('balanceOf', '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000'); 

viem

import { decodeFunctionResult, parseEther } from 'viem'
import { abi } from './abi'
 
const result = decodeFunctionResult({ 
  abi, 
  functionName: 'balanceOf', 
  data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', 
}) 

Interface.getSighash

Ethers

import { Interface, FunctionFragment } from '@ethersproject/abi';
 
const hash = Interface.getSighash(FunctionFragment.from('function ownerOf(uint256)')); 

viem

import { toFunctionHash } from 'viem'
 
const hash = toFunctionHash('function ownerOf(uint256)') 

Address Utilities

getAddress

Ethers

import { utils } from 'ethers'
 
const address = utils.getAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') 

viem

import { getAddress } from 'viem'
 
const address = getAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') 

isAddress

Ethers

import { utils } from 'ethers'
 
const address = utils.isAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') 

viem

import { isAddress } from 'viem'
 
const address = isAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') 

getContractAddress

Ethers

import { utils } from 'ethers'
 
const address = utils.getContractAddress({ from: '0x...', nonce: 5 }); 

viem

import { getContractAddress } from 'viem'
 
const address = getContractAddress({ from: '0x...', nonce: 5 }) 

getCreate2Address

Ethers

import { utils } from 'ethers'
 
const from = '0x8ba1f109551bD432803012645Ac136ddd64DBA72'; 
const salt = '0x7c5ea36004851c764c44143b1dcb59679b11c9a68e5f41497f6cf3d480715331'; 
const initCode = '0x6394198df16000526103ff60206004601c335afa6040516060f3'; 
const initCodeHash = utils.keccak256(initCode); 
 
const address = utils.getCreate2Address(from, salt, initCodeHash); 

viem

import { getContractAddress } from 'viem'
 
const address = getContractAddress({ 
  bytecode: '0x6394198df16000526103ff60206004601c335afa6040516060f3', 
  from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72', 
  opcode: 'CREATE2', 
  salt: '0x7c5ea36004851c764c44143b1dcb59679b11c9a68e5f41497f6cf3d480715331', 
}); 

BigNumber Utilities

Ethers

Many.

viem

None. We use browser native BigInt.

Byte Manipulation Utilities

isBytes

Ethers

import { utils } from 'ethers'
 
utils.isBytes(new Uint8Array([1, 69, 420])) 

viem

import { isBytes } from 'viem'
 
isBytes(new Uint8Array([1, 69, 420])) 

isHexString

Ethers

import { utils } from 'ethers'
 
utils.isHexString('0xdeadbeef') 

viem

import { isHex } from 'viem'
 
isHex('0xdeadbeef') 

isBytesLike

Ethers

import { utils } from 'ethers'
 
utils.isBytesLike('0xdeadbeef') 

viem

import { isBytes, isHex } from 'viem'
 
isBytes('0xdeadbeef') || isHex('0xdeadbeef') 

arrayify

Ethers

import { utils } from 'ethers'
 
utils.arrayify('0xdeadbeef') 

viem

import { toBytes } from 'viem'
 
toBytes('0xdeadbeef') 

hexlify

Ethers

import { utils } from 'ethers'
 
utils.hexlify(new Uint8Array([1, 69, 420])) 

viem

import { toHex } from 'viem'
 
toHex(new Uint8Array([1, 69, 420])) 

hexValue

Ethers

import { utils } from 'ethers'
 
utils.hexValue(1) 

viem

import { toHex } from 'viem'
 
toHex(1) 

formatBytes32String

Ethers

import { utils } from 'ethers'
 
utils.formatBytes32String('Hello world') 
// 0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000

viem

import { stringToHex } from 'viem'
 
stringToHex('Hello world', { size: 32 }) 
// 0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000

parseBytes32String

Ethers

import { utils } from 'ethers'
 
utils.parseBytes32String('0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000') 
// "Hello world"

viem

import { hexToString } from 'viem'
 
hexToString('0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000', { size: 32 }) 
// "Hello world"

concat

Ethers

import { utils } from 'ethers'
 
utils.concat([new Uint8Array([69]), new Uint8Array([420])]) 

viem

import { concat, toBytes } from 'viem'
 
concat([new Uint8Array([69]), new Uint8Array([420])]) 

stripZeros

Ethers

import { utils } from 'ethers'
 
utils.stripZeros(new Uint8Array([0, 0, 0, 0, 0, 69])) 

viem

import { trim } from 'viem'
 
trim(new Uint8Array([0, 0, 0, 0, 0, 69])) 

zeroPad

Ethers

import { utils } from 'ethers'
 
utils.zeroPad(new Uint8Array([69]), 32) 

viem

import { pad } from 'viem'
 
pad(new Uint8Array([69]), { size: 32 }) 

hexConcat

Ethers

import { utils } from 'ethers'
 
utils.hexConcat(['0x00000069', '0x00000420']) 

viem

import { concat, toBytes } from 'viem'
 
concat(['0x00000069', '0x00000420']) 

hexDataLength

Ethers

import { utils } from 'ethers'
 
utils.hexDataLength('0x00000069') 

viem

import { size } from 'viem'
 
size('0x00000069') 

hexDataSlice

Ethers

import { utils } from 'ethers'
 
utils.hexDataSlice('0x00000069', 4) 

viem

import { slice } from 'viem'
 
slice('0x00000069', 4) 

hexStripZeros

Ethers

import { utils } from 'ethers'
 
utils.hexStripZeros('0x00000069') 

viem

import { trim } from 'viem'
 
trim('0x00000069') 

hexZeroPad

Ethers

import { utils } from 'ethers'
 
utils.hexZeroPad('0x69', 32) 

viem

import { pad } from 'viem'
 
pad('0x69', { size: 32 }) 

Display Logic & Input Utilities

formatUnits

Ethers

import { utils } from 'ethers'
 
utils.formatUnits(BigNumber.from('1000000000'), 9) 

viem

import { formatUnits } from 'viem'
 
formatUnits(1000000000n, 9) 

formatEther

Ethers

import { utils } from 'ethers'
 
utils.formatEther(BigNumber.from('1000000000000000000')) 

viem

import { formatEther } from 'viem'
 
formatEther(1000000000000000000n) 

parseUnits

Ethers

import { utils } from 'ethers'
 
utils.parseUnits('1.0', 18) 

viem

import { parseUnits } from 'viem'
 
parseUnits('1', 18) 

parseEther

Ethers

import { utils } from 'ethers'
 
utils.parseEther('1.0') 

viem

import { parseEther } from 'viem'
 
parseEther('1') 

Encoding Utilities

RLP.encode

Ethers

import { utils } from 'ethers'
 
utils.RLP.encode('0x12345678') 

viem

import { toRlp } from 'viem'
 
toRlp('0x12345678') 

RLP.decode

Ethers

import { utils } from 'ethers'
 
utils.RLP.decode('0x8412345678') 

viem

import { fromRlp } from 'viem'
 
fromRlp('0x8412345678') 

Hashing Utilities

id

Ethers

import { utils } from 'ethers'
 
utils.id('function ownerOf(uint256 tokenId)') 
 
// hash utf-8 data
utils.id('hello world') 

viem

import { toFunctionSelector, keccak256, toHex } from 'viem'
 
toFunctionSelector('function ownerOf(uint256 tokenId)') 
 
// hash utf-8 data
keccak256(toHex('hello world')) 

keccak256

Ethers

import { utils } from 'ethers'
 
utils.keccak256(utils.toUtf8Bytes('hello world')) 

viem

import { keccak256, toBytes } from 'viem'
 
keccak256(toBytes('hello world')) 

encodeBase64/decodeBase64

viem does not provide Base64 encoding utilities.

You can use browser native atob and btoa instead.

encodeBase58/decodeBase58

viem does not provide Base58 encoding utilities.

You can use libraries such as base58-js or bs58 instead.

namehash

Ethers

import { utils } from 'ethers'
 
utils.namehash('awkweb.eth') 

viem

import { namehash } from 'viem'
 
namehash('awkweb.eth') 

solidityPack & solidityKeccak256

Ethers

import { utils } from 'ethers'
 
utils.solidityPack(['int16', 'uint48'], [-1, 12]) 
utils.solidityKeccak256(['int16', 'uint48'], [-1, 12]) 

viem

import { encodePacked, keccak256 } from 'viem'
 
encodePacked(['int16', 'uint48'], [-1, 12]) 
keccak256(encodePacked(['int16', 'uint48'], [-1, 12])) 

String Utilities

toUtf8Bytes

Ethers

import { utils } from 'ethers'
 
utils.toUtf8Bytes('Hello World') 

viem

import { stringToBytes } from 'viem'
 
stringToBytes('Hello World') 

toUtf8String

Ethers

import { utils } from 'ethers'
 
utils.toUtf8String(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])) 

viem

import { bytesToString } from 'viem'
 
bytesToString(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])) 

Transaction Utilities

serializeTransaction

Ethers

import { utils } from 'ethers'
 
const serialized = utils.serializeTransaction({
  chainId: 1,
  maxFeePerGas: utils.parseGwei('20'),
  maxPriorityFeePerGas: utils.parseGwei('2'),
  nonce: 69,
  to: "0x1234512345123451234512345123451234512345",
  type: 2,
  value: utils.parseEther('0.01'),
})

viem

import { serializeTransaction, parseEther, parseGwei } from 'viem'
 
const serialized = serializeTransaction({
  chainId: 1,
  gas: 21001n,
  maxFeePerGas: parseGwei('20'),
  maxPriorityFeePerGas: parseGwei('2'),
  nonce: 69,
  to: "0x1234512345123451234512345123451234512345",
  value: parseEther('0.01'),
})

parseTransaction

Ethers

import { utils } from 'ethers'
 
const transaction = utils.parseTransaction('0x02ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')

viem

import { parseTransaction } from 'viem'
 
const transaction = parseTransaction('0x02ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')