Skip to content
On this page

Ethers v5 โ†’ viem Migration Guide

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

ts
import { getDefaultProvider } from 'ethers'

const provider = getDefaultProvider()

viem

ts
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 interchangable with StaticJsonRpcProvider.

ts
import { providers } from 'ethers'

const provider = new providers.JsonRpcProvider('https://cloudflare-eth.com')

Custom Chain:

ts
import { providers } from 'ethers'

const provider = new providers.JsonRpcProvider('https://rpc.ankr.com/fantom/โ€‹', {
  name: 'Fantom',
  id: 250
})

viem

ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'

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

Custom Chain:

ts
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

ts
import { providers } from 'ethers'

const provider = new providers.InfuraProvider('homestead', '<apiKey>')

viem

ts
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

ts
import { providers } from 'ethers'

const provider = new providers.AlchemyProvider('homestead', '<apiKey>')

viem

ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'

const client = createPublicClient({
  chain: mainnet,
  transport: http('https://eth-mainnet.alchemyapi.io/v2/<apiKey>')
})

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

CloudflareProvider

Ethers

ts
import { providers } from 'ethers'

const provider = new providers.CloudflareProvider()

viem

ts
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

ts
import { providers } from 'ethers'

const provider = new providers.PocketProvider('homestead', '<apiKey>')

viem

ts
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

ts
import { providers } from 'ethers'

const provider = new providers.AnkrProvider('homestead', '<apiKey>')

viem

ts
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

ts
import { providers } from 'ethers'

const alchemy = new providers.AlchemyProvider('homestead', '<apiKey>')
const infura = new providers.AlchemyProvider('homestead', '<apiKey>')
const provider = new providers.FallbackProvider([alchemy, infura])

viem

ts
import { createPublicClient, http, fallback } from 'viem'
import { mainnet } from 'viem/chains'

const alchemy = http('https://eth-mainnet.alchemyapi.io/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

ts
import { providers } from 'ethers'

const provider = new providers.Web3Provider(window.ethereum)

viem

ts
import { createWalletClient, custom } from 'viem'

const client = createWalletClient({
  transport: custom(window.ethereum)
})

WebSocketProvider

Ethers

ts
import { providers } from 'ethers'

const provider = new providers.WebSocketProvider('wss://eth-mainnet.alchemyapi.io/v2/<apiKey>')

viem

ts
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'

const client = createPublicClient({
  chain: mainnet,
  transport: webSocket('wss://eth-mainnet.alchemyapi.io/v2/<apiKey>')
})

Signers โ†’ getAccount

JsonRpcSigner

Ethers

ts
import { providers } from 'ethers'

const provider = new providers.Web3Provider(window.ethereum)

const [address] = await provider.listAcconts()
const signer = provider.getSigner(address)

signer.sendTransaction({ ... })

viem

ts
import { createWalletClient, custom, getAccount } from 'viem'

const client = createWalletClient({
  transport: custom(window.ethereum)
})

const [address] = await client.getAddresses()
const account = getAccount(address)

client.sendTransaction({ account, ... })

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

Wallet

Ethers

ts
import { providers, Wallet } from 'ethers'

const provider = new providers.Web3Provider(window.ethereum)

const wallet = new Wallet('0x...', provider)

wallet.sendTransaction({ ... })

viem

viem does not currently support client-side signing โ€“ until then, you can use an Ethers Wallet:

ts
import { Wallet } from 'ethers'
import { createWalletClient, custom, getAccount } from 'viem'

const client = createWalletClient({
  transport: custom(window.ethereum)
})

const account = getAccount(new Wallet('0x...'))

client.sendTransaction({ account, ... })

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

Provider Methods

Ethers

ts
import { getDefaultProvider } from 'ethers'

const provider = getDefaultProvider()

provider.getBlock(...)
provider.getTransaction(...)
...

viem

ts
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

ts
import { providers } from 'ethers'

const provider = new providers.Web3Provider(window.ethereum)

const [address] = await provider.listAcconts()
const signer = provider.getSigner(address)

signer.sendTransaction(...)
signer.signMessage(...)
...

viem

ts
import { createWalletClient, custom, getAccount } from 'viem'

const client = createWalletClient({
  transport: custom(window.ethereum)
})

const [address] = await client.getAddresses()
const account = getAccount(address)

client.sendTransaction({ account, ... })
client.signMessage({ account, ... })
...

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.

Wallet

Ethers

ts
import { providers, Wallet } from 'ethers'

const provider = new providers.Web3Provider(window.ethereum)

const wallet = new Wallet('0x...', provider)

wallet.sendTransaction(...)
wallet.signMessage(...)
...

viem

viem does not currently support client-side signing โ€“ until then, you can use an Ethers Wallet:

ts
import { Wallet } from 'ethers'
import { createWalletClient, custom, getAccount } from 'viem'

const client = createWalletClient({
  transport: custom(window.ethereum)
})

const account = getAccount(new Wallet('0x...'))

client.sendTransaction({ account, ... })
client.signMessage({ account, ... })
...

Contract Interaction

Reading from Contracts

Ethers

ts
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

ts
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

ts
import { Contract, providers } from 'ethers'
import { wagmiContractConfig } from './abi'

const provider = new providers.Web3Provider(window.ethereum)

const [address] = await provider.listAcconts()
const signer = provider.getSigner(address)

const { abi, address } = wagmiContractConfig
const contract = new Contract(address, abi, signer)
const hash = await contract.mint()

viem

ts
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'

const publicClient = createPublicClient({
  chain: mainnet,
  transport: http()
})
const walletClient = createWalletClient({
  transport: custom(window.ethereum)
})

const [address] = await walletClient.getAddresses()
const account = getAccount(address)

const request = await publicClient.simulateContract({
  ...wagmiContractConfig,
  functionName: 'mint',
  account,
})
const supply = await walletClient.writeContract(request)

Deploying Contracts

Ethers

ts
import { ContractFactory, providers } from 'ethers'
import { abi, bytecode } from './abi'

const provider = new providers.Web3Provider(window.ethereum)

const [address] = await provider.listAcconts()
const signer = provider.getSigner(address)

const contract = new ContractFactory(abi, bytecode, signer)
await contract.deploy()

viem

ts
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { abi, bytecode } from './abi'

const walletClient = createWalletClient({
  transport: custom(window.ethereum)
})

const [address] = await walletClient.getAddresses()
const account = getAccount(address)

await walletClient.deployContract({
  abi,
  account,
  bytecode,
})

Contract Events

Ethers

ts
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

ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'

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

const unwatch = await 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

ts
import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'

const provider = getDefaultProvider()

const { abi, address } = wagmiContractConfig
const contract = new Contract(address, abi, provider)
const gas = contract.estimateGas.mint()

viem

ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'

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

const gas = client.estimateContractGas({
  ...wagmiContractConfig, 
  functionName: 'mint'
})

Call

Ethers

ts
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

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

ABI Utilities

abiCoder.encode

Ethers

ts
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

ts
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

ts
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

ts
import { decodeAbiParameters, parseAbiParameters } from 'viem'

// Object
decodeAbiParameters(
  [{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
  '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)

// Human Readable
decodeAbiParameters(
  parseAbiParameters('uint, string'),
  '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)

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

ts
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

ts
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

ts
import { utils } from 'ethers'

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

viem

ts
import { parseAbiItem } from 'viem'

const abiItem = parseAbiItem('function balanceOf(address owner) view returns (uint)')

ParamType.from

ethers

ts
import { utils } from 'ethers'

const param = utils.ParamType.from('address owner')

viem

ts
import { parseAbiParameter } from 'viem'

const param = parseAbiParameter('address owner')

Fragment Access

Ethers

ts
import { utils } from 'ethers'
import { abi } from './abi'

const interface = new utils.Interface(abi) 
interface.getFunction('transferFrom')
interface.getEvent('Transfer')

viem

ts
import { getAbiItem } from 'viem'
import { abi } from './abi'

getAbiItem({ abi, name: 'transferFrom' }) 
getAbiItem({ abi, name: 'Transfer' })

Interface.encodeDeploy

Ethers

ts
import { utils } from 'ethers'
import { abi } from './abi'

const iface = new utils.Interface(abi); 
const data = iface.encodeDeploy(['SYM', 'Some Name'])

viem

ts
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

ts
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

ts
import { encodeErrorResult, parseEther } from 'viem'
import { abi } from './abi'

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

Interface.encodeFilterTopics

Ethers

ts
import { utils } from 'ethers'
import { abi } from './abi'

const iface = new utils.Interface(abi); 
const data = iface.encodeFilterTopics('Transfer', [
  null,
  '0x8ba1f109551bD432803012645Ac136ddd64DBA72'
])

viem

ts
import { encodeEventTopics } from 'viem'
import { abi } from './abi'

const data = encodeEventTopics({ 
  abi,
  eventName: 'Transfer',
  args: {
    to: '0x8ba1f109551bD432803012645Ac136ddd64DBA72'
  }
})

Interface.encodeFunctionData

Ethers

ts
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

ts
import { encodeFunctionData, parseEther } from 'viem'
import { abi } from './abi'

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

Interface.encodeFunctionResult

Ethers

ts
import { utils } from 'ethers'
import { abi } from './abi'

const iface = new utils.Interface(abi); 
const data = iface.encodeFunctionResult('balanceOf', [
  '0x8ba1f109551bD432803012645Ac136ddd64DBA72'
])

viem

ts
import { encodeFunctionResult, parseEther } from 'viem'
import { abi } from './abi'

const data = encodeFunctionResult({ 
  abi,
  functionName: 'balanceOf',
  value: ['0x8ba1f109551bD432803012645Ac136ddd64DBA72']
})

Interface.decodeErrorResult

Ethers

ts
import { utils } from 'ethers'
import { abi } from './abi'

const iface = new utils.Interface(abi); 
const result = iface.decodeErrorResult("AccountLocked", '0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000')

viem

ts
import { decodeErrorResult, parseEther } from 'viem'
import { abi } from './abi'

const result = decodeErrorResult({ 
  abi,
  data: '0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000'
})

Interface.decodeEventLog

Ethers

ts
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

ts
import { decodeEventLog, parseEther } from 'viem'
import { abi } from './abi'

const result = decodeEventLog({ 
  abi,
  data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', 
  topics: [
    '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72',
    '0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c'
  ]
})

Interface.decodeFunctionData

Ethers

ts
import { utils } from 'ethers'
import { abi } from './abi'

const iface = new utils.Interface(abi); 
const result = iface.decodeFunctionData('transferFrom', '0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000');

viem

ts
import { decodeFunctionData, parseEther } from 'viem'
import { abi } from './abi'

const result = decodeFunctionData({ 
  abi,
  data: '0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000',
})

Interface.decodeFunctionResult

Ethers

ts
import { utils } from 'ethers'
import { abi } from './abi'

const iface = new utils.Interface(abi); 
const result = iface.decodeFunctionResult('balanceOf', '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000');

viem

ts
import { decodeFunctionResult, parseEther } from 'viem'
import { abi } from './abi'

const result = decodeFunctionResult({ 
  abi,
  functionName: 'balanceOf',
  data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000',
})

Address Utilities

getAddress

Ethers

ts
import { utils } from 'ethers'

const address = utils.getAddress('0x8ba1f109551bd432803012645ac136ddd64dba72')

viem

ts
import { getAddress } from 'viem'

const address = getAddress('0x8ba1f109551bd432803012645ac136ddd64dba72')

isAddress

Ethers

ts
import { utils } from 'ethers'

const address = utils.isAddress('0x8ba1f109551bd432803012645ac136ddd64dba72')

viem

ts
import { isAddress } from 'viem'

const address = isAddress('0x8ba1f109551bd432803012645ac136ddd64dba72')

getContractAddress

Ethers

ts
import { utils } from 'ethers'

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

viem

ts
import { getContractAddress } from 'viem'

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

getCreate2Address

Ethers

ts
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

ts
import { getContractAddress } from 'ethers'

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

ts
import { utils } from 'ethers'

utils.isBytes(new Uint8Array([1, 69, 420]))

viem

ts
import { isBytes } from 'viem'

isBytes(new Uint8Array([1, 69, 420]))

isHexString

Ethers

ts
import { utils } from 'ethers'

utils.isHexString('0xdeadbeef')

viem

ts
import { isHex } from 'viem'

isHex('0xdeadbeef')

isBytesLike

Ethers

ts
import { utils } from 'ethers'

utils.isBytesLike('0xdeadbeef')

viem

ts
import { isBytes, isHex } from 'viem'

isBytes('0xdeadbeef') || isHex('0xdeadbeef')

arrayify

Ethers

ts
import { utils } from 'ethers'

utils.arrayify('0xdeadbeef')

viem

ts
import { toBytes } from 'viem'

toBytes('0xdeadbeef')

hexlify

Ethers

ts
import { utils } from 'ethers'

utils.hexlify(new Uint8Array([1, 69, 420]))

viem

ts
import { toHex } from 'viem'

toHex(new Uint8Array([1, 69, 420]))

hexValue

Ethers

ts
import { utils } from 'ethers'

utils.hexValue(1)

viem

ts
import { toHex } from 'viem'

toHex(1)

concat

Ethers

ts
import { utils } from 'ethers'

utils.concat([new Uint8Array([69]), new Uint8Array([420])])

viem

ts
import { concat, toBytes } from 'viem'

concat([new Uint8Array([69]), new Uint8Array([420])])

stripZeros

Ethers

ts
import { utils } from 'ethers'

utils.stripZeros(new Uint8Array([0, 0, 0, 0, 0, 69]))

viem

ts
import { trim } from 'viem'

trim(new Uint8Array([0, 0, 0, 0, 0, 69]))

zeroPad

Ethers

ts
import { utils } from 'ethers'

utils.zeroPad(new Uint8Array([69]), 32)

viem

ts
import { pad } from 'viem'

pad(new Uint8Array([69]), { size: 32 })

hexConcat

Ethers

ts
import { utils } from 'ethers'

utils.hexConcat(['0x00000069', '0x00000420'])

viem

ts
import { concat, toBytes } from 'viem'

concat(['0x00000069', '0x00000420'])

hexDataLength

Ethers

ts
import { utils } from 'ethers'

utils.hexDataLength('0x00000069')

viem

ts
import { size } from 'viem'

size('0x00000069')

hexDataSlice

Ethers

ts
import { utils } from 'ethers'

utils.hexDataSlice('0x00000069', 4)

viem

ts
import { slice } from 'viem'

slice('0x00000069', 4)

hexStripZeros

Ethers

ts
import { utils } from 'ethers'

utils.hexStripZeros('0x00000069')

viem

ts
import { trim } from 'viem'

trim('0x00000069')

hexZeroPad

Ethers

ts
import { utils } from 'ethers'

utils.hexZeroPad('0x69', 32)

viem

ts
import { pad } from 'viem'

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

Display Logic & Input Utilities

formatUnits

Ethers

ts
import { utils } from 'ethers'

utils.formatUnits(BigNumber.from('1000000000'), 9)

viem

ts
import { formatUnits } from 'viem'

formatUnits(1000000000n, 9)

formatEther

Ethers

ts
import { utils } from 'ethers'

utils.formatEther(BigNumber.from('1000000000000000000'))

viem

ts
import { formatEther } from 'viem'

formatEther(1000000000000000000n)

parseUnits

Ethers

ts
import { utils } from 'ethers'

utils.parseUnits('1.0', 18)

viem

ts
import { parseUnits } from 'viem'

parseUnits('1', 18)

parseEther

Ethers

ts
import { utils } from 'ethers'

utils.parseEther('1.0')

viem

ts
import { parseUnits } from 'viem'

parseEther('1')

Encoding Utilities

RLP.encode

Ethers

ts
import { utils } from 'ethers'

utils.RLP.encode('0x12345678')

viem

ts
import { toRlp } from 'viem'

toRlp('0x12345678')

RLP.decode

Ethers

ts
import { utils } from 'ethers'

utils.RLP.decode('0x8412345678')

viem

ts
import { fromRlp } from 'viem'

toRlp('0x8412345678')

Hashing Utilities

id

Ethers

ts
import { utils } from 'ethers'

utils.id('function ownerOf(uint256 tokenId)')

// hash utf-8 data
utils.id('hello world')

viem

ts
import { getFunctionSelector, keccak256, toHex } from 'viem'

getFunctionSelector('function ownerOf(uint256 tokenId)')

// hash utf-8 data
keccak256(toHex('hello world'))

keccak256

Ethers

ts
import { utils } from 'ethers'

utils.keccak256(utils.toUtf8Bytes('hello world'))

viem

ts
import { keccak256, toBytes } from 'viem'

keccak256(toBytes('hello world'))

encodeBase64/decodeBase58

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

ts
import { utils } from 'ethers'

utils.namehash('awkweb.eth')

viem

ts
import { namehash } from 'viem'

namehash('awkweb.eth')

solidityPack & solidityKeccak256

Ethers

ts
import { utils } from 'ethers'

utils.solidityPack(['int16', 'uint48'], [-1, 12])
utils.solidityKeccak256(['int16', 'uint48'], [-1, 12])

viem

ts
import { encodePacked, keccak256 } from 'viem'

encodePacked(['int16', 'uint48'], [-1, 12])
keccak256(encodePacked(['int16', 'uint48'], [-1, 12]))

String Utilities

toUtf8Bytes

Ethers

ts
import { utils } from 'ethers'

utils.toUtf8Bytes('Hello World')

viem

ts
import { stringToBytes } from 'viem'

stringToBytes('Hello World')

toUtf8String

Ethers

ts
import { utils } from 'ethers'

utils.toUtf8String(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))

viem

ts
import { bytesToString } from 'viem'

bytesToString(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))

Released under the MIT License.