Migration Guide
If you are coming from an earlier version of viem
, you will need to make sure to update the following APIs listed below.
2.x.x Breaking changes
The 2.x.x release includes very minor breaking changes to the Contract Instances API, entrypoints, chain modules, and miscellaneous actions + utilities listed below.
Not ready to migrate? Head to the 1.x.x docs.
Actions: Modified getContract
Client API
The publicClient
and walletClient
parameters of the getContract
API has been removed in favour of client
to support Client's that extend (ie. a Wallet Client extended with Public Actions).
import { getContract } from 'viem'
import { publicClient, walletClient } from './client'
const contract = getContract({
abi,
address,
publicClient,
walletClient,
client: {
public: publicClient,
wallet: walletClient,
}
})
Removed entrypoints
The following entrypoints have been removed:
viem/abi
viem/contract
viem/public
viem/test
viem/wallet
You can import the entrypoints directly from viem
:
import { encodeAbiParameters } from 'viem/abi'
import { getContract } from 'viem/contract'
import { getBlock } from 'viem/public'
import { mine } from 'viem/test'
import { sendTransaction } from 'viem/wallet'
import {
encodeAbiParameters,
getContract,
getBlock,
mine,
sendTransaction,
} from 'viem'
Moved chain-specific exports in viem/chains/utils
Chain-specific exports in viem/chains/utils
have been moved to viem/{celo|op-stack|zksync}
:
import {
parseTransactionCelo,
parseTransaction
serializeTransactionCelo,
serializeTransaction
// ...
} from 'viem/chains/utils'
} from 'viem/celo'
import {
// ...
} from 'viem/chains/utils'
} from 'viem/op-stack'
import {
parseTransactionZkSync,
parseTransaction,
serializeTransactionZkSync,
serializeTransaction,
// ...
} from 'viem/chains/utils'
} from 'viem/zksync'
Actions: getBlockNumber
The maxAge
parameter has been removed in favor of cacheTime
.
const blockNumber = await client.getBlockNumber({
maxAge: 84_600
cacheTime: 84_600
})
Actions: OnLogFn
& OnLogParameter
types
The OnLogFn
& OnLogParameter
types have been renamed.
import {
OnLogFn,
WatchEventOnLogsFn,
OnLogParameter,
WatchEventOnLogsParameter,
} from 'viem'
Actions: prepareRequest
The prepareRequest
Action has been renamed to prepareTransactionRequest
and moved to viem/actions
entrypoint.
import {
prepareRequest,
prepareTransactionRequest,
} from 'viem'
} from 'viem/actions'
Actions: SimulateContractParameters
& SimulateContractReturnType
types
Note the following breaking generic slot changes:
type SimulateContractParameters<
TAbi,
TFunctionName,
TArgs, // Args added to Slot 2
TChain,
TChainOverride,
TAccountOverride,
>
type SimulateContractReturnType<
TAbi,
TFunctionName,
TArgs, // Args added to Slot 2
TChain,
TAccount, // Account added to Slot 4
TChainOverride,
TAccountOverride,
>
Utilities: Removed extractFunctionParts
, extractFunctionName
, extractFunctionParams
, extractFunctionType
The extractFunctionParts
, extractFunctionName
, extractFunctionParams
, extractFunctionType
utility functions have been removed. You can use the parseAbiItem
utility function from abitype instead.
Utilities: Renamed bytesToBigint
The bytesToBigint
utility function has been renamed to bytesToBigInt
.
import {
bytesToBigint,
bytesToBigInt,
} from 'viem'
Utilities: Renamed chain types
The following chain types have been renamed:
import {
Formatter,
ChainFormatter,
Formatters,
ChainFormatters,
Serializers,
ChainSerializers,
ExtractFormatterExclude,
ExtractChainFormatterExclude,
ExtractFormatterParameters,
ExtractChainFormatterParameters,
ExtractFormatterReturnType,
ExtractChainFormatterReturnType,
} from 'viem'
Utilties: isAddress
& getAddress
perform checksum validation
The isAddress
utility function now performs checksum validation by default.
To opt-out of this behavior, you can pass strict: false
or lowercase the address.
import { isAddress } from 'viem'
isAddress('0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', {
strict: false
})
isAddress(
'0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac'.toLowerCase()
)
1.x.x Breaking changes
The 1.x.x release only includes very minor changes to the behavior in event log decoding, and removes the redundant ethers.js Wallet Adapter. If you do not directly use these APIs, you do not need to update any of your code for this version.
Removed ethersWalletToAccount
The ethersWalletToAccount
adapter has been removed.
This adapter was introduced when viem did not have Private Key & HD Accounts. Since 0.2, viem provides all the utilities needed to create and import Private Key & HD Accounts.
If you still need it, you can copy + paste the old implementation.
logIndex
& transactionIndex
on Logs
logIndex
& transactionIndex
on Log
now return a number
instead of a bigint
.
const log: Log = {
...
logIndex: 1n,
logIndex: 1,
transactionIndex: 1n,
transactionIndex: 1,
...
}
Minor: decodeEventLog
behavior change
decodeEventLog
no longer attempts to partially decode events. If the Log does not conform to the ABI (mismatch between the number of indexed/non-indexed arguments to topics/data), it will throw an error.
For example, the following Log will throw an error as there is a mismatch in non-indexed
arguments & data
length.
decodeEventLog({
abi: parseAbi(['event Transfer(address indexed, address, uint256)']),
// `data` should be 64 bytes, but is only 32 bytes.
data: '0x0000000000000000000000000000000000000000000000000000000000000001'
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
]
})
Previously, the above would only decode the indexed
arguments.
If you would like to partially decode event logs (previous behavior), you can turn off strict
mode:
decodeEventLog({
abi: parseAbi(['event Transfer(address indexed, address, uint256)']),
data: '0x0000000000000000000000000000000000000000000000000000000000000001'
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
],
strict: false
})
0.3.x Breaking changes
The 0.3.x release only includes breaking changes around RPC errors. If you do not directly use the APIs listed below, you do not need to update any of your code for this version.
Renamed RequestError
to RpcError
RequestError
was renamed RpcError
for clarity.
import { RequestError } from 'viem'
import { RpcError } from 'viem'
throw new RequestError(new Error('An error occurred.'))
throw new RpcError(new Error('An error occurred.'))
Removed RpcRequestError
RpcRequestError
was removed. Use RpcError
instead.
import { RpcRequestError } from 'viem'
import { RpcError } from 'viem'
throw new RpcRequestError(new Error('An error occurred.'))
throw new RpcError(new Error('An error occurred.'))
Renamed RpcError
to RpcRequestError
RpcError
was renamed RpcRequestError
for consistency.
import { RpcError } from 'viem'
import { RpcRequestError } from 'viem'
const err = new RpcError({
const err = new RpcRequestError({
body: { foo: 'bar' },
error: { code: 420, message: 'Error' },
url: 'https://example-rpc.com',
})
0.2.x Breaking changes
chain
is required for sendTransaction
, writeContract
, deployContract
A chain is now required for the sendTransaction
, writeContract
, deployContract
Actions.
You can hoist the Chain on the Client:
import { createWalletClient, custom, getAccount } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
const account = getAccount('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
Alternatively, you can pass the Chain directly to the Action:
import { createWalletClient, custom, getAccount } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
const account = getAccount('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
const hash = await walletClient.sendTransaction({
account,
chain: mainnet,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
recoverAddress
, recoverMessageAddress
, verifyMessage
are now async
The following functions are now async
functions instead of synchronous functions:
recoverAddress
recoverMessageAddress
verifyMessage
import { recoverMessageAddress } from 'viem'
recoverMessageAddress({ message: 'hello world', signature: '0x...' })
await recoverMessageAddress({ message: 'hello world', signature: '0x...' })
assertChain
removed from sendTransaction
Removed assertChain
argument on sendTransaction
, writeContract
& deployContract
. If you wish to bypass the chain check (not recommended unless for testing purposes), you can pass chain: null
.
await walletClient.sendTransaction({
assertChain: false,
chain: null,
...
})
getAccount
removed
Removed the getAccount
function.
For JSON-RPC Accounts, use the address itself.
You can now pass the address directly to the account
option.
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const address = '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
const client = createWalletClient({
account: getAccount(address),
account: address,
chain: mainnet,
transport: custom(window.ethereum)
})
For Ethers Wallet Adapter, use ethersWalletToAccount
.
If you were using the Ethers Wallet adapter, you can use the ethersWalletToAccount
function.
Note: viem 0.2.0 now has a Private Key & Mnemonic Account implementation. You probably do not need this adapter anymore. This adapter may be removed in a future version.
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { getAccount } from 'viem/ethers'
import { ethersWalletToAccount } from 'viem/ethers'
import { Wallet } from 'ethers'
const account = getAccount(new Wallet('0x...'))
const account = ethersWalletToAccount(new Wallet('0x...'))
const client = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
})
For Local Accounts, use toAccount
.
If you are using a custom signing implementation, you can use the toAccount
function.
import { createWalletClient, http, getAccount } from 'viem'
import { createWalletClient, http } from 'viem'
import { toAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { getAddress, signMessage, signTransaction } from './sign-utils'
const privateKey = '0x...'
const account = getAccount({
const account = toAccount({
address: getAddress(privateKey),
signMessage(message) {
return signMessage(message, privateKey)
},
signTransaction(transaction) {
return signTransaction(transaction, privateKey)
},
signTypedData(typedData) {
return signTypedData(typedData, privateKey)
}
})
const client = createWalletClient({
account,
chain: mainnet,
transport: http()
})
data
renamed in signMessage
Renamed the data
parameter in signMessage
to message
.
walletClient.signMessage({
data: 'hello world',
message: 'hello world',
})