Migration Guide
If you are coming from an earlier version of wagmi
, you will need to make sure to update the following APIs listed below.
1.x.x Breaking changes
Not ready to migrate yet? You can find the 0.12.x
docs
here.
General
Removed ethers
peer dependency
The ethers
peer dependency has been removed in favour of viem
.
npm uninstall ethers
npm i wagmi viem@latest
If your project is using modules from ethers
directly, that are dependant on wagmi (e.g. BigNumber
, etc), you will need to migrate to the viem
-equivalent module. Check out the Ethers.js → viem migration guide.
If you have usages of ethers
that are independent of wagmi, it is highly recommended to migrate to viem
to take advantage of the smaller bundle size.
"Provider" & "Signer" terminology
Ethers Provider & Signer terminology is now known as viem's Public Client & Wallet Client terminology.
This directly affects:
createClient
configureChains
useProvider
(nowusePublicClient
)useSigner
(nowuseWalletClient
)useWebSocketProvider
(nowuseWebSocketPublicClient
)
createClient
import { WagmiConfig, createConfig } from 'wagmi'
- import { getDefaultProvider } from 'ethers'
+ import { createPublicClient, http } from 'viem'
const config = createConfig({
autoConnect: true,
- provider: getDefaultProvider(),
+ publicClient: createPublicClient({
+ chain: mainnet,
+ transport: http()
+ })
})
Note: You may notice that
createClient
is nowcreateConfig
. Don't worry – the migration for that is below.
configureChains
import { WagmiConfig, createConfig, configureChains, mainnet } from 'wagmi'
import { publicProvider } from 'wagmi/providers/public'
const {
chains,
- provider,
+ publicClient,
- webSocketProvider,
+ webSocketPublicClient
} = configureChains(
[mainnet],
[publicProvider()],
)
const config = createConfig({
autoConnect: true,
- provider,
+ publicClient,
- webSocketProvider,
+ webSocketPublicClient
})
useProvider
- import { useProvider } from 'wagmi'
+ import { usePublicClient } from 'wagmi'
- const provider = useProvider()
+ const publicClient = usePublicClient()
useSigner
- import { useSigner } from 'wagmi'
+ import { useWalletClient } from 'wagmi'
- const { data: signer } = useSigner()
+ const { data: walletClient } = useWalletClient()
useWebSocketProvider
- import { useWebSocketProvider } from 'wagmi'
+ import { useWebSocketPublicClient } from 'wagmi'
- const webSocketProvider = useWebSocketProvider()
+ const webSocketPublicClient = useWebSocketPublicClient()
Types
Provider
→PublicClient
Signer
→WalletClient
WebSocketProvider
→WebSocketPublicClient
createClient
→ createConfig
The createClient
function has been renamed to createConfig
.
- import { createClient } from 'wagmi'
+ import { createConfig } from 'wagmi'
- const client = createClient({
+ const config = createConfig({
...
})
useClient
→ useConfig
If you are using useClient
, that has been renamed to useConfig
:
- import { useClient } from 'wagmi'
+ import { useConfig } from 'wagmi'
- const client = useClient()
+ const config = useConfig()
BigNumber
→ native BigInt
All BigNumber
instances are now platform native BigInt
instances. This means you can no longer use arithmatic methods such as .add
, .subtract
, etc because BigInt
is just a primitive type like number
.
- const value = BigNumber.from('69420')
+ const value = 69420n
- const value = BigNumber.from('69420')
+ const value = 69420n
- const value2 = BigNumber.from('42069')
+ const value2 = 42069n
- const value3 = value.add(value2)
+ const value3 = value + value2
Using native BigInt
with JSON.stringify
will raise a TypeError
as
BigInt
values are not serializable. Read here for instructions to
mitigate.
from
has been renamed to account
The from
attribute has been renamed to account
. Directly affects Actions that consist of a from
parameter.
const { config } = usePrepareContractWrite({
...,
- from: '0x...'
+ account: '0x...'
})
gasLimit
has been renamed to gas
The gasLimit
attribute has been renamed to gas
, and still implies the same meaning. It was renamed to align closer to EIP-1474 and enforce consistency. Aligning closer to EIP-1474 means that you will not need to re-map from gas
to gasLimit
if you are deriving from an external source.
useSendTransaction({
request: {
to: 'jxom.eth',
- gasLimit: 69420n,
+ gas: 69420n,
value: 1n
}
})
Removed goerli
export
Removed the goerli
export from wagmi
. Goerli is now a deprecated testnet. You will now have to import it from wagmi/chains
.
-import { goerli } from 'wagmi'
+import { goerli } from 'wagmi/chains'
Removed window.ethereum
global type
The window.ethereum
global type has been removed in favor of an explicit wagmi/window
import.
+import 'wagmi/window';
const isMetaMask = window.ethereum.isMetaMask
Renamed the Ethereum
type to WindowProvider
The Ethereum
type has been renamed to WindowProvider
.
Hooks
useConnect
No longer returns the provider
property in data
. Use connector.getProvider()
instead.
const { data } = useConnect({
...
})
- const provider = data.provider
+ const provider = await data.connector.getProvider()
No longer returns the provider
property in connectAsync
return type. Use connector.getProvider()
instead.
const { connectAsync } = useConnect({
...
})
const result = await connectAsync(...)
- const provider = result.provider
+ const provider = await result.connector.getProvider()
useBalance
Returns a bigint
instead of BigNumber
Returns a bigint
instead of BigNumber
for data.value
. Maps to viem's getBalance
.
const { data } = useBalance({
...
})
const value = data.value
// ^? const value: bigint
useBlockNumber
Returns a bigint
instead of number
Returns a bigint
instead of number
for data
. Maps to viem's getBlockNumber
.
const { data } = useBlockNumber({
// ^? const data: bigint
...
})
useContract
Hook Removed.
Use the getContract
Action instead or declarative Hook (e.g. useContractRead
, useContractWrite
, etc.).
- import { useContract } from 'wagmi'
+ import { getContract } from 'wagmi/actions'
useEnsAvatar
Replaced address
with name
Replaced address
with name
in order to remove internal async call to resolve address
to name
. Maps to viem's getEnsAvatar
.
+ const { data: ensName } = useEnsName({
+ address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
+ })
const { data: avatar } = useEnsAvatar({
- address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
+ name: ensName,
})
useFeeData
Return type changes
Returns bigint
instead of a BigNumber
for gasPrice
, maxFeePerGas
, and maxPriorityFeePerGas
.
const { data } = useFeeData()
data.gasPrice
// ^? const gasPrice: bigint
data.maxFeePerGas
// ^? const maxFeePerGas: bigint
data.maxPriorityFeePerGas
// ^? const maxPriorityFeePerGas: bigint
useProvider
Renamed to usePublicClient
Returns viem Public Client instead of ethers Provider
.
- const provider = useProvider(...)
+ const publicClient = usePublicClient(...)
useSigner
Renamed to getWalletClient
Returns viem Wallet Client instead of ethers Signer
.
- const { data } = useSigner(...)
// ^? const data: Signer
+ const { data } = useWalletClient(...)
// ^? const data: WalletClient
useToken
Returns a bigint
Returns bigint
instead of a BigNumber
for totalSupply.value
.
const { data } = useToken({
...
})
const value = data.totalSupply.value
// ^? const value: bigint
useTransaction
Returns viem Transaction
Returns viem Transaction
instead of an ethers Transaction
. Maps to viem's getTransaction
.
const { data } = useTransaction({
// ^? const data: Transaction
...
})
useContractReads
Return type structure changed
When allowFailure
is truthy (default), the return structure is now in the form of { error, result, status }[]
instead of an array of contract function results (Result[]
).
const { data } = useContractReads({
...
})
- const result = data[0]
+ const { result } = data[0]
The return type when allowFailure
is falsy has not changed.
Removed console.warn
logs for failing contract methods
The console.warn
logs for failing contract methods has been removed. Failing methods can now be extracted from the error
property of the return type.
const { data } = useContractReads({
...
})
+ useEffect(() => {
+ if (data)
+ data.forEach(({ error, status }) => {
+ if (status === 'failure') console.warn(error.message)
+ })
+ }, [data])
Removed overrides
The overrides
parameter has been removed in favor of top-level blockNumber
& blockTag
parameters.
const { data } = useContractReads({
...
- overrides: {
- blockTag: 'safe'
- }
+ blockTag: 'safe'
})
useContractInfiniteReads
Return type structure changed
When allowFailure
is truthy (default), the return structure is now in the form of { error, result, status }[]
instead of an array of contract function results (Result[]
).
const { data } = useContractInfiniteReads({
...
})
- const result = data.pages[0][0]
+ const { result } = data.pages[0][0]
The return type when allowFailure
is falsy has not changed.
Removed console.warn
logs for failing contract methods
The console.warn
logs for failing contract methods has been removed. Failing methods can now be extracted from the error
property of the return type.
const { data } = useContractInfiniteReads({
...
})
+ useEffect(() => {
+ if (data)
+ data.pages.flat().forEach(({ error, status }) => {
+ if (status === 'failure') console.warn(error.message)
+ })
+ }, [data])
Removed overrides
The overrides
parameter has been removed in favor of top-level blockNumber
& blockTag
parameters.
const { data } = useContractInfiniteReads({
...
- overrides: {
- blockTag: 'safe'
- }
+ blockTag: 'safe'
})
usePrepareSendTransaction
Removed request
The request
parameter has been removed in favor of top-level parameters. Maps to viem's sendTransaction
parameters.
const { config } = usePrepareSendTransaction({
- request: {
- to: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
- value: BigNumber.from('69420'),
- },
+ to: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
+ value: 69420n
})
usePrepareContractWrite
Removed overrides
The overrides
parameter has been removed in favor of top-level parameters. Maps to viem's simulateContract
parameters.
const { config } = usePrepareContractWrite({
address: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
abi: wagmigotchiABI,
functionName: 'feed',
- overrides: {
- from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
- value: BigNumber.from('69420'),
- },
+ account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
+ value: 69420n
})
Return type structure changed
The returned config.request
now returns the shape of viem's WriteContractParameters
, instead of Ethers' TransactionRequest
.
Removed abi
, address
, functionName
from the return value, they now belong in config.request
.
useContractEvent
Callback now returns array of logs
Callback now returns an array of Event Logs (with included decoded args), instead of positional decoded args with the log.
const unwatch = useContractEvent({
address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
abi: ensRegistryABI,
eventName: 'NewOwner',
- listener: (node, label, owner) => {
+ listener: (logs) => {
- console.log(node, label, owner)
+ const { args } = logs[0]
+ console.log(args.node, args.label, args.owner)
},
})
Removed once
The once
parameter has been removed. Use unwatch
to cleanup the listener instead.
const unwatch = useContractEvent({
address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
abi: ensRegistryABI,
eventName: 'NewOwner',
- once: true,
listener: (logs) => {
const { args } = logs[0]
console.log(args.node, args.label, args.owner)
+ unwatch()
}
})
useContractRead
Removed overrides
The overrides
parameter has been removed in favor of top-level blockNumber
& blockTag
parameters.
const { data } = useContractRead({
...
- overrides: {
- blockTag: 'safe'
- }
+ blockTag: 'safe'
})
useContractWrite
Removed requirement for "prepare" mode
Removed the requirement for "prepare" mode. You can now use useContractWrite
without calling usePrepareContractWrite
first.
const { data, isLoading, isSuccess, write } = useContractWrite({
- mode: 'recklesslyUnprepared',
address: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
abi: wagmigotchiABI,
functionName: 'claim',
tokenId: 69,
})
wait
has been removed from the return type
wait
has been removed from the return type, favor waitForTransaction
instead.
+ import { waitForTransaction } from 'wagmi/actions'
const { data } = useContractWrite(...)
const {
- wait,
+ hash,
} = data || {}
- const receipt = await wait()
+ const receipt = await waitForTransaction({ hash })
Removed overrides
The overrides
parameter has been removed in favor of top-level parameters. Maps to viem's writeContract
parameters.
const { config } = useContractWrite({
...
- overrides: {
- gasLimit: BigNumber.from('42069'),
- value: BigNumber.from('69420'),
- },
+ gasLimit: 42069n,
+ value: 69420n
})
Renamed recklesslySetUnpreparedArgs
to args
const { data, write } = useContractWrite({
...
})
write({
- recklesslySetUnpreparedArgs: [69],
+ args: [69],
})
Removed recklesslySetUnpreparedOverrides
Removed recklesslySetUnpreparedOverrides
. They now exist at the top-level of the function.
const { data, write } = useContractWrite({
...
})
write({
- recklesslySetUnpreparedOverrides: {
- gasLimit: BigNumber.from('42069'),
- value: BigNumber.from('69420'),
- },
+ gas: 42069n,
+ value: 69420n
})
Return type changed
Now returns a viem TransactionReceipt instead of an Ethers TransactionReceipt
.
useSendTransaction
Removed requirement for "prepare" mode
Removed the requirement for "prepare" mode. You can now use useContractWrite
without calling usePrepareContractWrite
first.
const { data, isLoading, isSuccess, sendTransaction } = useSendTransaction({
- mode: 'recklesslyUnprepared',
request: {
to: 'moxey.eth',
value: BigNumber.from('10000000000000000'),
}
})
Removed request
The request
parameter has been removed in favor of top-level parameters. Maps to viem's sendTransaction
parameters.
const { hash } = useSendTransaction({
...
- request: {
- to: 'jxom.eth',
- value: BigNumber.from('69420'),
- },
+ to: 'jxom.eth',
+ value: 69420n
})
Renamed recklesslySetUnpreparedRequest
to request
const { sendTransaction } = useSendTransaction({
...
})
write({
- recklesslySetUnpreparedRequest: { ... },
+ request: { ... },
})
wait
has been removed from the return type
wait
has been removed from the return type, favor waitForTransaction
instead.
+ import { waitForTransaction } from 'wagmi/actions'
const { data } = useSendTransaction(...)
const {
- wait,
+ hash,
} = data || {}
- const receipt = await wait()
+ const receipt = await waitForTransaction({ hash })
useSignMessage
message
no longer accepts a byte array
message
no longer accepts a byte array, only a string value
useSignTypedData
value
has been renamed to message
const signature = useSignTypedData({
domain,
types,
primaryType: 'Mail',
- value,
+ message
})
primaryType
is now required
The primaryType
attribute is now required. Aligns closer to EIP-712, and allows consumers to specify an alternative primary type. Previously, Ethers.js did some internal stuff to figure out the primary type. But it's not hard for a consumer to just provide that – and we believe it is more clear.
const signature = useSignTypedData({
domain,
types,
+ primaryType: 'Mail',
message
})
useWaitForTransaction
Renamed onSpeedUp
to onReplaced
const waitForTransaction = useWaitForTransaction({
hash: '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060',
- onSpeedUp: (transaction) => console.log(transaction),
+ onReplaced: (transaction) => console.log(transaction)
})
useWatchPendingTransactions
Callback now returns batched transaction hashes
The callback now returns a batched array of transaction hashes, instead of callback being emitted several times with singular hashes.
useWatchPendingTransactions(
- listener: (hash) => console.log(hash),
+ listener: (hashes) => console.log(hashes[0]),
)
useWebSocketProvider
Renamed to useWebSocketPublicClient
Returns viem Public Client instead of ethers Provider
.
- const webSocketProvider = useWebSocketProvider(...)
+ const webSocketPublicClient = useWebSocketPublicClient(...)
configureChains
Removed quorum support
Removed quorum support: priority
, minQuorum
and targetQuorum
(for now). viem does not support quorum in the fallback
Transport yet, but will in the future!
Connectors
The breaking changes below only applies if you are building a Connector on top of wagmi.
Renamed getSigner
to getWalletClient
The getSigner
method has been renamed to getWalletClient
, and also returns viem's WalletClient
instead of an Ethers.js Signer
- async getSigner({ chainId }: { chainId?: number } = {}) {
+ async getWalletClient({ chainId }: { chainId?: number } = {}) {
const [provider, account] = await Promise.all([
this.getProvider(),
this.getAccount(),
])
+ const chain = this.chains.find((x) => x.id === chainId) || this.chains[0]
- return new providers.Web3Provider(
- provider,
- chainId,
- ).getSigner(account)
+ return createWalletClient({
+ account,
+ chain,
+ transport: custom(provider),
+ })
}
Errors
ChainDoesNotSupportMulticallError
Use ChainDoesNotSupportContract
from viem instead.
ContractMethodDoesNotExistError
Use ContractFunctionExecutionError
from viem instead.
ContractMethodNoResultError
Use ContractFunctionZeroDataError
from viem instead.
ContractMethodRevertedError
Use ContractFunctionRevertedError
from viem instead.
ContractResultDecodeError
Use ContractFunctionExecutionError
from viem instead.
ProviderRpcError
Use ProviderRpcError
from viem instead.
ResourceUnavailableError
Use ResourceUnavailableRpcError
from viem instead.
0.12.x Breaking changes
WalletConnectConnector
WalletConnect v1 has been sunset and WalletConnectConnector
now uses WalletConnect v2 by default.
wagmi still supports WalletConnect v1 via a WalletConnectLegacyConnector
, however, it is recommended to migrate to WalletConnect v2. Instructions can be found here.
If you are already using WalletConnect v2:
The version
flag has been omitted, and qrcode
has been renamed to showQrModal
.
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect'
const connector = new WalletConnectConnector({
options: {
- version: '2',
projectId: '...',
- qrcode: true,
+ showQrModal: true,
},
})
Read more on WalletConnectConnector
If you are still using WalletConnect v1:
You must migrate to the WalletConnect v2
Connector before June 28, after which, the
WalletConnectLegacyConnector
will be removed.
-import { WalletConnectConnector } from 'wagmi/connectors/walletConnect'
+import { WalletConnectLegacyConnector } from 'wagmi/connectors/walletConnectLegacy'
-const connector = new WalletConnectConnector({
+const connector = new WalletConnectLegacyConnector({
options: {
qrcode: true,
},
})
Read more on WalletConnectLegacyConnector
0.11.x Breaking changes
Not ready to migrate yet? You can find the 0.10.x
docs
here.
Upgrade to typescript@>=4.9.4
TypeScript 5.0 is coming soon and has some great features we are excited to bring into wagmi. To prepare for this, update your TypeScript version to 4.9.4 or higher. There are likely no breaking changes if you are coming from typescript@4.7.x || typescript@4.8.x
.
0.10.x Breaking changes
Not ready to migrate yet? You can find the 0.9.x
docs
here.
useSigner
The useSigner
hook now always returns undefined
when no signer is present. Previously, it returned null
or undefined
.
When no signer is present, the hook will be in an "idle"
status.
0.9.x Breaking changes
Not ready to migrate yet? You can find the 0.8.x
docs
here.
Chain exports
With the introduction of the wagmi/chains
entrypoint, wagmi
no longer exports the following:
chain
allChains
defaultChains
defaultL2Chains
chainId
etherscanBlockExplorers
alchemyRpcUrls
,infuraRpcUrls
,publicRpcUrls
Read below for migration steps.
Removed chain
The chain
export has been removed. wagmi
now only exports the mainnet
& goerli
chains. If you need to use an alternative chain (polygon
, optimism
, etc), you will need to import it from the wagmi/chains
entrypoint.
import {
- chain
configureChains
} from 'wagmi'
+ import { mainnet, polygon, optimism } from 'wagmi/chains'
const { ... } = configureChains(
- [chain.mainnet, chain.polygon, chain.optimism],
+ [mainnet, polygon, optimism],
{
...
}
)
Removed allChains
The allChains
export has been removed. If you need a list of all chains, you can utilize wagmi/chains
entrypoint.
- import { allChains } from 'wagmi'
+ import * as allChains from 'wagmi/chains'
const { ... } = configureChains(allChains, ...)
Removed defaultChains
& defaultL2Chains
The defaultChains
& defaultL2Chains
exports have been removed. If you still need the defaultChains
or defaultL2Chains
exports, you can build them yourself:
- import { defaultChains } from 'wagmi'
+ import { mainnet, goerli } from 'wagmi/chains'
+ const defaultChains = [mainnet, goerli]
The
defaultChains
export was previously populated withmainnet
&goerli
.
- import { defaultL2Chains } from 'wagmi'
+ import {
+ arbitrum,
+ arbitrumGoerli,
+ polygon,
+ polygonMumbai,
+ optimism,
+ optimismGoerli
+ } from 'wagmi/chains'
+ const defaultL2Chains = [
+ arbitrum,
+ arbitrumGoerli,
+ polygon,
+ polygonMumbai,
+ optimism
+ optimismGoerli
+ ]
The
defaultL2Chains
export was previously populated witharbitrum
&optimism
.
Removed chainId
The chainId
export has been removed. You can extract a chain ID from the chain itself.
- import { chainId } from 'wagmi'
+ import { mainnet, polygon, optimism } from 'wagmi/chains'
-const mainnetChainId = chainId.mainnet
-const polygonChainId = chainId.polygon
-const optimismChainId = chainId.optimism
+const mainnetChainId = mainnet.id
+const polygonChainId = polygon.id
+const optimismChainId = optimism.id
Removed etherscanBlockExplorers
The etherscanBlockExplorers
export has been removed. You can extract a block explorer from the chain itself.
- import { etherscanBlockExplorers } from 'wagmi'
+ import { mainnet, polygon, optimism } from 'wagmi/chains'
-const mainnetEtherscanBlockExplorer = etherscanBlockExplorers.mainnet
-const polygonEtherscanBlockExplorer = etherscanBlockExplorers.polygon
-const optimismEtherscanBlockExplorer = etherscanBlockExplorers.optimism
+const mainnetEtherscanBlockExplorer = mainnet.blockExplorers.default
+const polygonEtherscanBlockExplorer = polygon.blockExplorers.default
+const optimismEtherscanBlockExplorer = optimism.blockExplorers.default
Removed alchemyRpcUrls
, infuraRpcUrls
& publicRpcUrls
The alchemyRpcUrls
, infuraRpcUrls
& publicRpcUrls
exports have been removed. You can extract a RPC URL from the chain itself.
- import { alchemyRpcUrls, infuraRpcUrls, publicRpcUrls } from 'wagmi'
+ import { mainnet } from 'wagmi/chains'
-const mainnetAlchemyRpcUrl = alchemyRpcUrls.mainnet
-const mainnetInfuraRpcUrl = infuraRpcUrls.mainnet
-const mainnetOptimismRpcUrl = publicRpcUrls.mainnet
+const mainnetAlchemyRpcUrl = mainnet.rpcUrls.alchemy
+const mainnetInfuraRpcUrl = mainnet.rpcUrls.infura
+const mainnetOptimismRpcUrl = mainnet.rpcUrls.optimism
Chain
type
RPC URLs
The rpcUrls
shape has changed to include an array of URLs, and also the transport method (http
or webSocket
):
type Chain = {
...
rpcUrls: {
- [key: string]: string
+ [key: string]: {
+ http: string[]
+ webSocket: string[]
+ }
}
...
}
Note that you will also need to ensure that usage is migrated:
- const rpcUrl = mainnet.rpcUrls.alchemy
+ const rpcUrl = mainnet.rpcUrls.alchemy.http[0]
Contracts
The multicall
and ens
attributes have been moved into the contracts
object:
type Contract = {
address: Address
blockCreated?: number
}
type Chain = {
...
- multicall: Contract
- ens: Contract
+ contracts: {
+ multicall3: Contract
+ ensRegistry: Contract
+ }
...
}
Note that you will also need to ensure that usage is migrated:
- const multicallContract = mainnet.multicall
+ const multicallContract = mainnet.contracts.multicall3
useEnsResolver
Behavioral changes
useEnsResolver
's result is no longer persisted by the query client since it cannot serialize its prototype methods.
Configuration changes
Removed the cacheTime
and staleTime
config options.
const { data } = useEnsResolver({
name: 'wagmi-dev.eth',
- cacheTime: 2000,
- staleTime: 2000,
})
useWaitForTransaction
Behavioral changes
useWaitForTransaction
will now return an error
(and invoke the onError
callback) if the transaction has been reverted or cancelled.
Configuration changes
Removed the wait
config option on useWaitForTransaction
. Use the transaction hash
instead.
const { data } = useWaitForTransaction({
- wait: transaction.wait,
+ hash: transaction.hash,
})
0.8.x Breaking changes
Not ready to migrate yet? You can find the 0.7.x
docs
here.
CommonJS Support Dropped
wagmi no longer supports CommonJS and only supports ES Modules. If you are using modern tooling, like Next.js, Vite, or Vitest, you likely don't need to do anything! Remix and Jest require some additional configuration. Check out this guide for more info on ESM support and Frequently Asked Questions across various tools and setups.
Deprecated chains removed
Removed the following deprecated chains:
ropsten
rinkeby
kovan
optimismKovan
arbitrumRinkeby
If you feel you still need to include one of these testnets in your application, you will have to define it manually:
-import { chain } from 'wagmi'
+import { Chain } from 'wagmi'
-export const rinkeby = chain.rinkeby
+export const rinkeby: Chain = {
+ id: 4,
+ name: 'Rinkeby',
+ network: 'rinkeby',
+ nativeCurrency: { name: 'Rinkeby Ether', symbol: 'ETH', decimals: 18 },
+ rpcUrls: {
+ alchemy: 'https://eth-rinkeby.alchemyapi.io/v2',
+ default: 'https://rpc.ankr.com/eth_rinkeby',
+ infura: 'https://rinkeby.infura.io/v3',
+ public: 'https://rpc.ankr.com/eth_rinkeby',
+ },
+ blockExplorers: {
+ etherscan: 'https://rinkeby.etherscan.io',
+ default: 'https://rinkeby.etherscan.io',
+ },
+ ens: {
+ address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
+ },
+ multicall: {
+ address: '0xca11bde05977b3631167028862be2a173976ca11',
+ blockCreated: 10299530,
+ },
+ testnet: true,
}
You can reference these removed chains here.
alchemyProvider
Made apiKey
required on alchemyProvider
.
import { configureChains } from 'wagmi'
const config = configureChains(defaultChains, [
- alchemyProvider(),
+ alchemyProvider({ apiKey: process.env.ALCHEMY_API_KEY })
])
You can find your Alchemy API key from the Alchemy Dashboard, or your Infura API key from the Infura Dashboard.
infuraProvider
Made apiKey
required on infuraProvider
.
import { configureChains } from 'wagmi'
const config = configureChains(defaultChains, [
- infuraProvider(),
+ infuraProvider({ apiKey: process.env.INFURA_API_KEY })
])
You can find your Infura API key from the Infura Dashboard, or your Infura API key from the Infura Dashboard.
useBalance
Configuration changes
addressOrName
renamed to address
.
const result = useBalance({
- addressOrName: '0x…',
+ address: '0x…',
})
If you were using an ENS name instead of an address, you can resolve the name to an address before passing it to the action. This allows the ENS-to-address resolution to be cached instead of being wasted work before.
+ const { data: address } = useEnsAddress({ name: 'example.eth' })
const result = useBalance({
- addressOrName: 'example.eth',
+ address,
})
useEnsAvatar
Configuration changes
addressOrName
renamed to address
.
const result = useEnsAvatar({
- addressOrName: '0x…',
+ address: '0x…',
})
If you were using an ENS name instead of an address, you can resolve the name to an address before passing it to the action. This allows the ENS-to-address resolution to be cached instead of being wasted work before.
+ const { data: address } = useEnsAddress({ name: 'example.eth' })
const result = useEnsAvatar({
- addressOrName: 'example.eth',
+ address,
})
0.7.x Breaking changes
Not ready to migrate yet? You can find the 0.6.x
docs
here.
Upgrade to typescript@>=4.7.4
wagmi can now infer types based on ABI and EIP-712 Typed Data definitions, giving you full end-to-end type-safety from your contracts to your frontend and incredible developer experience (e.g. autocomplete ABI function names and catch misspellings, type ABI function arguments, etc.).
For this to work, you must upgrade to typescript@>=4.7.4
. Why is TypeScript v4.7.4 or greater necessary? TypeScript 4.7.4 introduced the ability
to extend constraints on inferred type variables, which is used extensively to help narrow types for ABIs. Good news! When upgrading TypeScript from 4.6 to 4.7 there are likely no breaking changes for your set up.
See the wagmi TypeScript docs for more information on TypeScript support in this version.
When switching over to inferring types based on your ABIs, you may notice
TypeScript complaining about types that worked fine before. For example, Type 'string' is not assignable to type 'BigNumber'
. Previously, you were able to
use string
types in place of BigNumber
types, BigNumber
types in place
of number
types, etc.
The types inferred directly from ABIs are more correct and strict so you will
need to convert your types to match. This should be pretty straightforward by
following the error from TypeScript. Based on the error above, args: ['123']
should be updated to args: [BigNumber.from('123')]
.
addressOrName
and contractInterface
renamed for contract hooks
addressOrName
and contractInterface
renamed to address
and abi
respectively for the following contract hooks: useContract
, useContractEvent
, useContractRead
, useContractReads
, useContractInfiniteReads
, useContractWrite
, and usePrepareContractWrite
.
import { useContractRead } from 'wagmi'
const result = useContractRead({
- addressOrName: '0x…',
+ address: '0x…',
- contractInterface: […],
+ abi: […],
functionName: 'balanceOf',
args: ['0x…'],
})
If you were using an ENS name instead of an address, you can resolve the name to an address before passing it to the action.
- import { useContractRead } from 'wagmi'
+ import { useContractRead, useEnsAddress } from 'wagmi'
+ const { data: address } = useEnsAddress({ name: 'example.eth' })
const result = useContractRead({
- addressOrName: 'example.eth',
+ address,
abi: […],
functionName: 'balanceOf',
args: ['0x…'],
})
args
type changed for contract hooks
args
config option must now be an array for the following hooks: useContractRead
, useContractWrite
, usePrepareContractWrite
, useContractReads
, and useContractInfiniteReads
.
const { data } = useContractRead({
address: '0x…',
abi: […],
functionName: 'balanceOf',
- args: '0x…',
+ args: ['0x…'],
})
useContractEvent
Configuration changes
signerOrProvider
was removed.
useContractInfiniteReads
Configuration changes
Updated paginatedIndexesConfig
fn
parameter return type. fn
now returns an array instead of a single object.
useContractInfiniteReads({
cacheKey: 'contracts',
...paginatedIndexesConfig(
- (index) => ({
+ (index) => [{
address: '0x…',
abi: […],
functionName: 'tokenURI',
args: [BigNumber.from(index)] as const,
- }),
+ }],
{ start: 0, perPage: 10, direction: 'increment' },
),
})
usePrepareContractWrite
Behavioral changes
Throws an error when a chainId
is specified and the end-user is on a different chain id (the wrong network). If you wish to defer this check until the click handler is pressed, you can place the chainId
in useContractWrite
instead.
usePrepareSendTransaction
Behavioral changes
- The
usePrepareSendTransaction
hook will now only run when the end-user is connected to their wallet. This is to reach parity withusePrepareContractWrite
. If the end-user is not connected, then theusePrepareSendTransaction
hook will remain idle. - Throws an error when a
chainId
is specified and the end-user is on a different chain id (the wrong network). If you wish to defer this check until the click handler is pressed, you can placechainId
inuseContractWrite
instead.
0.6.x Breaking changes
Not ready to migrate yet? You can find the 0.5.x
docs
here.
All the breaking changes in this release are related to the introduction of Prepare Hooks. It is recommended to read the Prepare Hooks section before migrating to 0.6.x.
useContractWrite
Not ready to migrate to the new useContractWrite
yet? You can use the
useDeprecatedContractWrite
hook.
Behavioral changes
If a chainId
is passed to useContractWrite
, it will no longer attempt to switch chain before sending the transaction. Instead, it will throw an error if the user is on the wrong chain.
Why? Eagerly prompting to switch chain in these actions created a long-running async task that makes iOS App Links vulnerable.
Configuration changes
The configuration passed to the useContractWrite
hook now needs to be either:
- prepared with the
usePrepareContractWrite
Prepare Hook (new), or - recklessly unprepared (previous functionality)
Why? To avoid long-running asynchronous tasks in event handlers. Read more about Prepare Hooks.
Prepared usage
+const { config } = usePrepareContractWrite({
+ addressOrName: '0x...',
+ contractInterface: wagmiAbi,
+ functionName: 'mint',
+ args: [tokenId]
+})
const { data } = useContractWrite({
- addressOrName: '0x...',
- contractInterface: wagmiAbi,
- functionName: 'mint',
- args: [tokenId],
+ ...config
})
Recklessly unprepared usage
If you are not ready to upgrade to usePrepareContractWrite
, it is possible to use useContractWrite
without preparing the configuration first by passing mode: 'recklesslyUnprepared'
.
const { data } = useContractWrite({
+ mode: 'recklesslyUnprepared',
addressOrName: '0x...',
contractInterface: wagmiAbi,
functionName: 'mint',
args: [tokenId],
})
Return value changes
data
now only returns hash
& wait
data
now returns an object only consisting of hash
& wait
, and not the full TransactionResponse
.
If you require the full TransactionResponse
, you can use useTransaction
:
const {
data: {
hash,
wait,
- ...transaction
}
} = useContractWrite(...)
+const { data: transaction } = useTransaction({ hash })
Why? The old implementation of
useContractWrite
created a long-running async task, causing UX pitfalls when invoked in a click handler.
write
/writeAsync
arguments
The write
/writeAsync
configuration object has now been altered to only accept "reckless" configuration. If one or more of these values are set, it can lead to UX pitfalls.
<button
onClick={() => {
write({
- args: [1],
- overrides: { from: '0x...' }
+ recklesslySetUnpreparedArgs: [1],
+ recklesslySetUnpreparedOverrides: '0x...'
})
}}
>
Send
</button>
write
/writeAsync
can be undefined
When useContractWrite
is in "prepare mode" (used with usePrepareContractWrite
), write
/writeAsync
will be undefined
until the configuration has been prepared. Ensure that your usage reflects this.
const { config } = usePrepareContractWrite({ ... })
const { write } = useContractWrite(config)
<button
disabled={!write}
onClick={() => write?.()}
>
Send
</button>
useSendTransaction
Not ready to migrate to the new useSendTransaction
yet? You can use the
useDeprecatedSendTransaction
hook.
Behavioral changes
If a chainId
is passed to useSendTransaction
, it will no longer attempt to switch chain before sending the transaction. Instead, it will throw an error if the user is on the wrong chain.
Why? Eagerly prompting to switch chain in these actions created a long-running async task that makes iOS App Links vulnerable.
Configuration changes
The configuration passed to the useSendTransaction
hook now needs to be either:
- prepared with the
usePrepareSendTransaction
Prepare Hook (new), or - recklessly unprepared (previous functionality)
Why? To avoid long-running asynchronous tasks in event handlers. Read more about Prepare Hooks.
Prepared usage
import { usePrepareSendTransaction, useSendTransaction } from 'wagmi'
+const { config } = usePrepareSendTransaction({
+ request: {
+ to: 'moxey.eth',
+ value: parseEther('1'),
+ }
+})
const { data } = useSendTransaction({
- request: {
- to: 'moxey.eth',
- value: parseEther('1')
- }
+ ...config
})
Recklessly unprepared usage
If you are not ready to upgrade to usePrepareSendTransaction
, it is possible to use useSendTransaction
without preparing the configuration first by passing mode: 'recklesslyUnprepared'
.
import { useSendTransaction } from 'wagmi'
const { data } = useSendTransaction({
+ mode: 'recklesslyUnprepared',
request: {
to: 'moxey.eth',
value: parseEther('1'),
}
})
Return value changes
data
now only returns hash
& wait
data
now returns an object only consisting of hash
& wait
, and not the full TransactionResponse
.
If you require the full TransactionResponse
, you can use useTransaction
:
const {
data: {
hash,
wait,
- ...transaction
}
} = useSendTransaction(...)
+const { data: transaction } = useTransaction({ hash })
Why? The old implementation of
useSendTransaction
created a long-running async task, causing UX pitfalls when invoked in a click handler.
sendTransaction
/sendTransactionAsync
arguments
The sendTransaction
/sendTransactionAsync
configuration object has now been altered to only accept "reckless" configuration. If one or more of these values are set, it can lead to UX pitfalls.
<button
onClick={() => {
sendTransaction({
- request: {
+ recklesslySetUnpreparedRequest:
to: 'moxey.eth',
value: parseEther('1')
}
})
}}
>
Send
</button>
sendTransaction
/sendTransactionAsync
can be undefined
When useSendTransaction
is in "prepare mode" (used with usePrepareSendTransaction
), sendTransaction
/sendTransactionAsync
will be undefined
until the configuration has been prepared. Ensure that your usage reflects this.
const { config } = usePrepareSendTransaction({ ... })
const { sendTransaction } = useSendTransaction(config)
<button
disabled={!sendTransaction}
onClick={() => sendTransaction?.()}
>
Send
</button>
alchemyProvider
and infuraProvider
alchemyProvider
and infuraProvider
now use a generic apiKey
configuration option instead of alchemyId
and infuraId
.
import { alchemyProvider } from 'wagmi/providers/alchemy'
import { infuraProvider } from 'wagmi/providers/infura'
alchemyProvider({
- alchemyId: 'yourAlchemyApiKey',
+ apiKey: 'yourAlchemyApiKey',
})
infuraProvider({
- infuraId: 'yourInfuraApiKey',
+ apiKey: 'yourInfuraApiKey',
})
0.5.x Breaking changes
Not ready to migrate yet? You can find the 0.4.x
docs
here.
WagmiConfig
The client
prop is now required on WagmiConfig
.
```tsx
import {
createClient,
+ configureChains,
+ defaultChains
} from 'wagmi'
+import { publicProvider } from 'wagmi/providers/public'
+const { provider, webSocketProvider } = configureChains(defaultChains, [
+ publicProvider(),
+])
+const client = createClient({
+ provider,
+ webSocketProvider,
+})
function App() {
return (
<WagmiConfig
+ client={client}
>
<YourRoutes />
</WagmiConfig>
)
}
createClient
provider
is now required
The provider
config option is now required on createClient
. It is recommended to pass the provider
given from configureChains
.
import {
createClient,
+ defaultChains,
+ configureChains
} from 'wagmi'
+import { publicProvider } from 'wagmi/providers/publicProvider'
+const { provider } = configureChains(defaultChains, [
+ publicProvider
+])
const client = createClient({
+ provider
})
If you previously used an ethers.js Provider, you now need to provide your chains
on the Provider instance:
import {
createClient,
+ defaultChains
} from 'wagmi'
import ethers from 'ethers'
const client = createClient({
- provider: getDefaultProvider()
+ provider: Object.assign(getDefaultProvider(), { chains: defaultChains })
})
chainId
removed from connectors
Removed the chainId
parameter from connectors
function on createClient
.
const client = createClient({
- connectors({ chainId }) {
+ connectors() {
...
}
})
If you previously derived RPC URLs from the chainId
on connectors
, you can now remove that logic as wagmi
now handles RPC URLs internally when used with configureChains
.
import {
chain,
+ configureChains,
createClient
} from 'wagmi';
+import { publicProvider } from 'wagmi/providers/public'
import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet'
import { InjectedConnector } from 'wagmi/connectors/injected'
import { MetaMaskConnector } from 'wagmi/connectors/metaMask'
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect'
+const { chains } = configureChains(
+ [chain.mainnet],
+ [publicProvider()]
+);
const client = createClient({
- connectors({ chainId }) {
- const chain = chains.find((x) => x.id === chainId) ?? defaultChain
- const rpcUrl = chain.rpcUrls.alchemy
- ? `${chain.rpcUrls.alchemy}/${alchemyId}`
- : chain.rpcUrls.default
- return [
+ connectors: [
new MetaMaskConnector({ chains }),
new CoinbaseWalletConnector({
chains,
options: {
appName: 'wagmi',
- chainId: chain.id,
- jsonRpcUrl: rpcUrl,
},
}),
new WalletConnectConnector({
chains,
options: {
qrcode: true,
- rpc: { [chain.id]: rpcUrl },
},
}),
new InjectedConnector({
chains,
options: { name: 'Injected' },
}),
]
- },
})
useAccount
Return value changes
The data
value is now address
& connector
{
- data?: {
- address: string
- connector: Connector
- }
+ address?: string
+ connector?: Connector
}
Global connection status values have been added
The following global connection status values have been added:
{
+ isConnecting: boolean
+ isReconnecting: boolean
+ isConnected: boolean
+ isDisconnected: boolean
+ status: 'connecting' | 'reconnecting' | 'connected' | 'disconnected'
}
The useAccount
hook is now aware of any connection event in your application, so now you can use these connection status values to determine if your user is connected, disconnected or connecting to a wallet on a global scope.
error
, states & refetch
values have been removed
Since the useAccount
hook never dealt with asynchronous data, all of these values were
redundant & unused.
{
- error?: Error
- isIdle: boolean
- isLoading: boolean
- isFetching: boolean
- isSuccess: boolean
- isError: boolean
- isFetched: boolean
- isRefetching: boolean
- refetch: (options: {
- throwOnError: boolean
- cancelRefetch: boolean
- }) => Promise<{
- address: string
- connector: Connector
- }>
- status: 'idle' | 'error' | 'loading' | 'success'
}
Summary of changes
Below is the whole diff of changes to the useAccount
return value.
{
- data?: {
- address: string
- connector: Connector
- }
+ address?: string
+ connector?: Connector
- error?: Error
- isIdle: boolean
- isLoading: boolean
- isFetching: boolean
- isSuccess: boolean
- isError: boolean
- isFetched: boolean
- isRefetching: boolean
+ isConnecting: boolean
+ isReconnecting: boolean
+ isConnected: boolean
+ isDisconnected: boolean
- refetch: (options: {
- throwOnError: boolean
- cancelRefetch: boolean
- }) => Promise<{
- address: string
- connector: Connector
- }>
- status: 'idle' | 'error' | 'loading' | 'success'
+ status: 'connecting' | 'reconnecting' | 'connected' | 'disconnected'
}
Configuration changes
onConnect
has been added
The onConnect
callback is invoked when the account connects.
It provides the connected address & connector, as well as a isReconnected
flag for if the user reconnected via autoConnect
.
const account = useAccount({
onConnect({ address, connector, isReconnected }) {
console.log('Connected')
},
})
onDisconnect
has been added
The onDisconnect
callback is invoked when the account disconnected.
const account = useAccount({
onDisconnect() {
console.log('Disconnected')
},
})
suspense
has been removed
The useAccount
hook is a synchronous hook – so suspense
never worked.
const account = useAccount({
- suspense: true,
})
onError
has been removed
The useAccount
hook never had any error definitions – so onError
was never invoked.
const account = useAccount({
- onError(error) {
- console.log('Error', error)
- },
})
onSettled
has been removed
The useAccount
hook is a synchronous hook. onSettled
was always invoked immediately.
const account = useAccount({
- onSettled(data) {
- console.log('Settled', data)
- },
})
If you used onSettled
, you can move the code beneath the useAccount
hook:
const account = useAccount({
- onSettled(data) {
- console.log('Address:', data.address)
- },
})
+ console.log('Address:', account.address)
onSuccess
has been removed
The useAccount
hook is a synchronous hook. onSuccess
was always invoked immediately.
const account = useAccount({
- onSuccess(data) {
- console.log('Success', data)
- },
})
If you used onSuccess
, you can move the code beneath the useAccount
hook:
const account = useAccount({
- onSuccess(data) {
- console.log('Address:', data.address)
- },
})
+ console.log('Address:', account.address)
useConnect
Return value changes
Connection status flags have been moved
The isConnected
, isConnecting
, isReconnecting
& isDisconnected
flags have been moved to the useAccount
hook.
-import { useConnect } from 'wagmi'
+import { useAccount } from 'wagmi'
function App() {
const {
isConnected,
isConnecting,
isReConnecting,
isDisconnected
- } = useConnect()
+ } = useAccount()
}
New connect
mutation status flags have been added
The isLoading
, isSuccess
and isError
flags have been added to useConnect
.
These flags represent the local async state of useConnect
.
activeConnector
has been removed
The activeConnector
value has been removed. You can find the active connector on useAccount
.
-import { useConnect } from 'wagmi'
+import { useAccount } from 'wagmi'
function App() {
- const { activeConnector } = useConnect()
+ const { connector } = useAccount()
}
connector
parameter on connect
& connectAsync
has been removed
The connector
parameter on connect
& connectAsync
now has to be in the config object parameter shape.
import { useConnect } from 'wagmi'
function App() {
const { connect, connectors } = useConnect()
return (
<button
- onClick={() => connect(connectors[0])}
+ onClick={() => connect({ connector: connectors[0] })}
>
Connect
</button>
)
}
Configuration changes
onBeforeConnect
has been renamed
The onBeforeConnect
callback has been renamed to onMutate
onConnect
has been renamed
The onConnect
callback has been renamed to onSuccess
useContractRead
The useContractRead
hook parameters have been consolidated into a singular config parameter.
Before:
useContractRead(
{
addressOrName: wagmigotchiContractAddress,
contractInterface: wagmigotchiABI,
},
'love',
{ args: '0x27a69ffba1e939ddcfecc8c7e0f967b872bac65c' },
)
After:
useContractRead({
addressOrName: wagmigotchiContractAddress,
contractInterface: wagmigotchiABI,
functionName: 'love',
args: '0x27a69ffba1e939ddcfecc8c7e0f967b872bac65c',
})
useContractWrite
The useContractWrite
hook parameters have been consolidated into a singular config parameter.
Before:
useContractWrite(
{
addressOrName: mlootContractAddress,
contractInterface: mlootABI,
},
'claim',
)
After:
useContractWrite({
addressOrName: mlootContractAddress,
contractInterface: mlootABI,
functionName: 'claim',
})
useContractEvent
The useContractEvent
hook parameters have been consolidated into a singular config parameter.
Before:
useContractEvent(
{
addressOrName: uniContractAddress,
contractInterface: erc20ABI,
},
'Transfer',
listener,
),
After:
useContractEvent({
addressOrName: uniContractAddress,
contractInterface: erc20ABI,
eventName: 'Transfer',
listener,
})
useNetwork
The "switch network" functionality has been moved out of useNetwork
into a new useSwitchNetwork
hook.
The useNetwork
hook now accepts no configuration and only returns chain
(renamed from activeChain
) and chains
.
import {
useNetwork
+ useSwitchNetwork
} from 'wagmi'
const {
- activeChain
+ chain,
chains,
- data,
- error,
- isError,
- isIdle,
- isLoading,
- isSuccess,
- pendingChainId,
- switchNetwork,
- switchNetworkAsync,
- status,
- reset,
-} = useNetwork({
- chainId: 69,
- onError(error) {},
- onMutate(args) {},
- onSettled(data, error) {},
- onSuccess(data) {}
-})
+} = useNetwork()
+const {
+ chains,
+ data,
+ error,
+ isError,
+ isIdle,
+ isLoading,
+ isSuccess,
+ pendingChainId,
+ switchNetwork,
+ switchNetworkAsync,
+ status,
+ reset,
+} = useSwitchNetwork({
+ chainId: 69,
+ onError(error) {},
+ onMutate(args) {},
+ onSettled(data, error) {},
+ onSuccess(data) {}
+})
Connector
getProvider
Connector
s getProvider
method no longer supports the create
config parameter. Use the chainId
config option instead to force create a new provider.
0.4.x Breaking changes
Not ready to migrate yet? You can find the 0.3.x
docs
here.
createClient
Passing a function to createClient
connectors
has now been deprecated.
If you previously derived an RPC URL from the chainId
in connectors
, you will need to migrate to use the configureChains
API.
Before:
import { providers } from 'ethers'
import { Provider, chain, createClient, defaultChains } from 'wagmi'
import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet'
import { InjectedConnector } from 'wagmi/connectors/injected'
import { MetaMaskConnector } from 'wagmi/connectors/metaMask'
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect'
const alchemyId = process.env.ALCHEMY_ID
const chains = defaultChains
const defaultChain = chain.mainnet
const client = createClient({
autoConnect: true,
connectors({ chainId }) {
const chain = chains.find((x) => x.id === chainId) ?? defaultChain
const rpcUrl = chain.rpcUrls.alchemy
? `${chain.rpcUrls.alchemy}/${alchemyId}`
: chain.rpcUrls.default
return [
new MetaMaskConnector({ chains }),
new CoinbaseWalletConnector({
chains,
options: {
appName: 'wagmi',
chainId: chain.id,
jsonRpcUrl: rpcUrl,
},
}),
new WalletConnectConnector({
chains,
options: {
qrcode: true,
rpc: { [chain.id]: rpcUrl },
},
}),
new InjectedConnector({
chains,
options: {
name: 'Injected',
shimDisconnect: true,
},
}),
]
},
})
After:
import { Provider, chain, createClient, defaultChains } from 'wagmi'
import { alchemyProvider } from 'wagmi/providers/alchemy'
import { publicProvider } from 'wagmi/providers/public'
import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet'
import { InjectedConnector } from 'wagmi/connectors/injected'
import { MetaMaskConnector } from 'wagmi/connectors/metaMask'
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect'
const alchemyId = process.env.ALCHEMY_ID
const { chains } = configureChains(defaultChains, [
alchemyProvider({ alchemyId }),
publicProvider(),
])
const client = createClient({
autoConnect: true,
connectors: [
new MetaMaskConnector({ chains }),
new CoinbaseWalletConnector({
chains,
options: {
appName: 'wagmi',
},
}),
new WalletConnectConnector({
chains,
options: {
qrcode: true,
},
}),
new InjectedConnector({
chains,
options: {
name: 'Injected',
shimDisconnect: true,
},
}),
],
})
Duplicate named exports were removed
Duplicate exports with different names and the same functionality were removed to simplify the public API. In addition, confusing exports were renamed to be more descriptive.
createWagmiClient
alias was removed. UsecreateClient
instead.useWagmiClient
alias was removed. UseuseClient
instead.WagmiClient
alias was removed. UseClient
instead.createWagmiStorage
alias was removed. UsecreateStorage
instead.Provider
was renamed andWagmiProvider
alias is now deprecated. UseWagmiConfig
instead.
0.3.x Breaking changes
Not ready to migrate yet? You can find the 0.2.x
docs
here.
Provider
The Provider
component no longer supports configuration directly as props. You will now need to create a wagmi Client
via createClient
, and then pass the client to Provider
:
Before:
import { Provider } from 'wagmi'
function App() {
return (
<Provider autoConnect connectors={connectors} provider={provider}>
<YourRoutes />
</Provider>
)
}
After:
import { Provider, createClient } from 'wagmi'
const client = createClient({
autoConnect: true,
connectors,
provider,
})
function App() {
return (
<Provider client={client}>
<YourRoutes />
</Provider>
)
}
Hooks now return a singular object
All hooks in wagmi now return a single object instead of an array pair.
Before:
const [{ data, loading, error }, disconnect] = useAccount()
After:
const { data, isLoading, error } = useAccount()
Declarative getters > imperative getters
Getter functions such as getBalance
, getBlockNumber
, read
, etc have been removed in favor of hook parameters / refetch
. The refetch
function does not accept arguments/config, so you will need to restructure your components more declaratively.
Before:
import { useBalance } from 'wagmi'
function Example() {
const [address, setAddress] = useState<string>('')
const [{ data }, getBalance] = useBalance({
skip: true,
})
return (
<div>
Get balance:
<input onChange={(e) => setAddress(e.target.value)} value={address} />
<button onClick={() => getBalance({ addressOrName: address })}>
fetch
</button>
</div>
)
}
After:
import { useContractRead } from 'wagmi'
function Example() {
const [address, setAddress] = useState<string>('')
const { data, refetch } = useBalance({
addressOrName: address,
enabled: Boolean(address),
})
const [value, setValue] = useState<string>('')
return (
<div>
Get balance:
<input onChange={(e) => setValue(e.target.value)} value={value} />
<button
onClick={() => (address === value ? refetch() : setAddress(value))}
>
fetch
</button>
</div>
)
}
useAccount
- Now returns a singular object, instead of an array pair
fetchEns
was removed in favor of keepinguseAccount
as lightweight as possible. UseuseEnsName
anduseEnsAvatar
instead.disconnect
was removed. UseuseDisconnect
instead.
Before:
const [{ data, loading, error }, disconnect] = useAccount({ fetchEns: true })
After:
const { data, isLoading, error } = useAccount({ ens: true })
const { data: ensName } = useEnsName()
const { data: ensAvatar } = useEnsAvatar()
const { disconnect } = useDisconnect()
useBalance
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.getBalance
was removed in favor of hook parameters /refetch
. Before:
const [{ data, loading, error }, getBalance] = useBalance({ skip: true })
After:
const { data, isLoading, error, refetch } = useBalance({ enabled: false })
useBlockNumber
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.getBlockNumber
was removed in favor of hook parameters /refetch
. Before:
const [{ data, loading, error }, getBlockNumber] = useBlockNumber({
skip: true,
})
After:
const { data, isLoading, error, refetch } = useBlockNumber({
enabled: false,
})
useConnect
- Now returns a singular object, instead of an array pair
connect
is no longer asynchronous. UseconnectAsync
instead.data.connected
no longer exists. UseisConnected
instead.data.connectors
no longer exists. Useconnectors
instead.- Prefer
connector
overdata.connector
Before:
const [{ data, loading, error }, connect] = useConnect()
After:
const { isConnected, connector, connectors, connectAsync } = useConnect()
useContractRead
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.read
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, read] = useContractRead(
{
addressOrName: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
contractInterface: wagmigotchiABI,
},
'getHunger',
{ skip: true },
)
After:
const { data, error, isLoading, refetch } = useContractRead(
{
addressOrName: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
contractInterface: wagmigotchiABI,
},
'getHunger',
{ enabled: false },
)
useContractWrite
- Now returns a singular object, instead of an array pair Before:
const [{ data, error, loading }, write] = useContractWrite(
{
addressOrName: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
contractInterface: wagmigotchiABI,
},
'feed',
)
After:
const { data, error, isLoading, write } = useContractWrite(
{
addressOrName: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
contractInterface: wagmigotchiABI,
},
'feed',
)
useEnsAvatar
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.getEnsAvatar
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, getEnsAvatar] = useEnsAvatar({
addressOrName: 'awkweb.eth',
skip: true,
})
After:
const { data, error, isLoading, refetch } = useEnsAvatar({
addressOrName: 'awkweb.eth',
enabled: false,
})
useEnsLookup
useEnsLookup
was renamed touseEnsName
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.lookupAddress
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, lookupAddress] = useEnsLookup({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
skip: true,
})
After:
const { data, error, isLoading, refetch } = useEnsName({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
enabled: false,
})
useEnsResolveName
useEnsResolveName
was renamed touseEnsAddress
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.resolveName
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, resolveName] = useEnsResolveName({
name: 'meagher.eth',
skip: true,
})
After:
const { data, error, loading, refetch } = useEnsAddress({
name: 'meagher.eth',
enabled: false,
})
useEnsResolver
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.getEnsResolver
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, getEnsResolver] = useEnsResolver({
name: 'awkweb.eth',
skip: true,
})
After:
const { data, error, isLoading, refetch } = useEnsResolver({
name: 'awkweb.eth',
enabled: false,
})
useFeeData
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.getFeeData
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, getFeeData] = useFeeData({ skip: true })
After:
const { data, error, isLoading, refetch } = useFeeData({ enabled: false })
useNetwork
- Now returns a singular object, instead of an array pair
data.chain
is nowactiveChain
data.chains
is nowchains
switchNetwork
now has sync (switchNetwork
) and async (switchNetworkAsync
) variants. Before:
const [{ data, error, loading }, switchNetwork] = useNetwork()
After:
const { activeChain, chains, data, isLoading, switchNetworkAsync } =
useNetwork()
useSigner
- Now returns a singular object, instead of an array pair
skip
is no longer supported.getSigner
was removed in favor ofrefetch
Before:
const [{ data, error, loading }, getSigner] = useSigner()
After:
const { data, error, isLoading, refetch } = useSigner()
useSignMessage
- Now returns a singular object, instead of an array pair
signMessage
now has sync (signMessage
) and async (signMessageAsync
) variants. Before:
const [{ data, error, loading }, signMessage] = useSignMessage({
message: 'gm wagmi frens',
})
After:
const { data, error, isLoading, signMessageAsync } = useSignMessage({
message: 'gm wagmi frens',
})
useSignTypedData
- Now returns a singular object, instead of an array pair
signTypedData
now has sync (signTypedData
) and async (signTypedDataAsync
) variants. Before:
const [{ data, error, loading }, signTypedData] = useSignTypedData({
domain,
types,
value,
})
After:
const { data, error, isLoading, signTypedDataAsync } = useSignTypedData({
domain,
types,
value,
})
useToken
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.getToken
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, getToken] = useToken({
address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
skip: true,
})
After:
const { data, error, isLoading, refetch } = useToken({
address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
enabled: false,
})
useTransaction
useTransaction
was renamed touseSendTransaction
- Now returns a singular object, instead of an array pair
sendTransaction
now has sync (sendTransaction
) and async (sendTransactionAsync
) variants. Before:
const [{ data, error, loading }, sendTransaction] = useTransaction({
request: {
to: 'awkweb.eth',
value: parseEther('1'), // 1 ETH
},
})
After:
const { data, error, isLoading, sendTransactionAsync } = useSendTransaction({
request: {
to: 'awkweb.eth',
value: parseEther('1'), // 1 ETH
},
})
useWaitForTransaction
- Now returns a singular object, instead of an array pair
skip
is no longer supported. It was repurposed toenabled
.wait
was removed in favor of hook parameters /refetch
. Before:
const [{ data, error, loading }, wait] = useWaitForTransaction({
hash: '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060',
skip: true,
})
After:
const { data, error, isLoading, refetch } = useWaitForTransaction({
hash: '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060',
enabled: false,
})
connector.getProvider
connector.getProvider
is now asynchronous
Before:
const { connector } = useConnect()
const provider = connector.getProvider()
After:
const { connector } = useConnect()
const provider = await connector.getProvider()
WalletLinkConnector
The WalletLink connector was replaced with the Coinbase Wallet SDK.
Before:
import { WalletLinkConnector } from 'wagmi/connectors/walletLink'
const connector = new WalletLinkConnector({
options: {
appName: 'Mirror.xyz',
jsonRpcUrl: 'https://mainnet.infura.io/v3',
},
})
After:
import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet'
const connector = new CoinbaseWalletConnector({
options: {
appName: 'Mirror.xyz',
jsonRpcUrl: 'https://mainnet.infura.io/v3',
},
})