How to send an Ethereum transaction using Wagmi
In this tutorial, we are going to learn how to send an Ethereum transaction from the wallet connected to your React app using Wagmi.
In this tutorial, we are going to learn how to send an Ethereum transaction from the wallet connected to your React app using Wagmi.
Depending on the network that your Wagmi client is on, this same code will send the native token of the blockchain you're on. For example, it will send BNB on the Binance Smart Chain, FTM on Fantom, AVAX on Avalanche, etc...
Here is an example of how to do it:
import { useSendTransaction, usePrepareSendTransaction } from 'wagmi'
import { utils } from 'ethers';
function MyComponent() {
const { config } = usePrepareSendTransaction({
request: {
to: '0x5F70Ddd9908B04f952b9cB2A6F8E4D451725ceDC',
value: utils.parseEther('0.1'),
},
})
const { data, isLoading, isSuccess, isError, sendTransaction } =
useSendTransaction(config)
return (
<div>
<button disabled={!sendTransaction} onClick={() => sendTransaction?.()}>
Send 0.1 ETH
</button>
{isLoading && (
<span>Waiting for confirmation on your wallet</span>
)}
{isSuccess && (
<span>
The transaction was sent, waiting for it to be completed
</span>
)}
{isError && (
<span>You rejected the transaction on your wallet</span>
)}
</div>
)
}
Preparing and sending the transaction
First, we need to prepare the transaction by creating a config object using the usePrepareSendTransaction
hook.
In the example above, I configure a transaction to send 0.1 ETH to this address: 0x5F70Ddd9908B04f952b9cB2A6F8E4D451725ceDC
.
We will see all the properties you can set to configure your transaction below.
Next, we need to call the useSendTransaction
hook and pass the config we created in the parameters of the hook.
This hook returns the following properties:
data
: an object containing data about the transaction. Immediately after sending the transaction, it has 2 properties:
•hash
: the transaction hash
•wait
: a function that you can call to wait for the transaction to complete (more information about it below)error
: if the transaction could not be sent, it will contain information about what went wrong. One of the reasons the transaction could not be sent is if the user rejects the transaction on their wallet. If that happens, this property will contain an error saying that the user rejected the transaction.
Otherwise, before sending the transaction and after successfully sending the transaction it'snull
.isLoading
: will betrue
after you callsendTransaction
while waiting for the user to confirm the transaction on their wallet. Otherwise it'sfalse
.isError
: a boolean indicating if trying to send the transaction resulted in an error or not. It'strue
whenerror
is notnull
andfalse
otherwise.isSuccess
: a boolean indicating if the transaction was successfully sent or not. Before callingsendTransaction
, it's alsofalse
.status
: It will be"idle"
before sending the transaction,"error"
if there is an error,"loading"
when it's loading and"success"
after successfully sending the transaction
Using these properties, you can adjust your UI depending on what happened with the transaction.
Now, there are a few parameters you can pass to the useSendTransaction
hook but the most important ones are:
request
: an object containing all the parameters of the actual request on the blockchain. The properties you can pass to that object are defined by the Ethers library (the library that Wagmi is based on). You can find all the information about the properties you can pass here.
If you want to be more guided, you can check out our article on how to send Ethereum transactions using Ethers. There is a section called "The transaction parameters object" that contains all the information you need.
The simplestrequest
object you can pass is like the one in the example above, just theto
property containing the address that receives the ether and avalue
property that contains the amount to send inwei
, that's why I use theparseEther
function from Ethers. I use it to change the unit of the amount to send and convert if fromether
towei
.chainId
: (optional) the chain ID on which to send the transaction. You might need it if your app supports multiple chains.
Another thing that is good to know is that you can define callback functions to run when the data
, error
or isLoading
properties change:
const { data, sendTransaction } = useSendTransaction({
...config,
onSuccess: (data) => console.log('SUCCESS', data),
onError: (error) => console.log('ERROR', error),
onSettled: (data, error) => console.log('SETTLED', data, error),
});
As you can see, if you do that, you need to pass the config a bit differently.
You can pass:
onSuccess
which receives in parameter thedata
of the transaction (thehash
property and thewait
function). It will be run when the transaction was accepted by the user.onError
which receives in parameter the error and will be run if the transaction could not be sent (for example if the user rejects it).onSettled
which will be executed when the transaction is being processed by the blockchain. It runs right afteronSuccess
and takes in parameter thedata
and the eventualerror
.
If you want to see all the options you can pass, check out the documentation here:
Waiting for the transaction to be completed
Now, as you may have noticed, even if you send the transaction successfully, it doesn't mean the transaction was completed successfully. It can still fail. One of the reasons it can fail is if the wallet that sends this transaction doesn't have enough funds to pay for gas fees.
So after you send your transaction successfully, you can wait for the transaction to be confirmed and validated on the blockchain. For that, you have 2 options:
- Use the
wait
function contained in thedata
property returned byuseSendTransaction
. - Use the
useWaitForTransaction
hook.
Here is an example of how to wait for the transaction to complete using the wait
function or the useWaitForTransaction
hook:
import { useEffect } from 'react';
import { useSendTransaction, usePrepareSendTransaction, useWaitForTransaction } from 'wagmi';
import { utils } from 'ethers';
export const MyComponent = () => {
const { config } = usePrepareSendTransaction({
request: {
to: '0x5F70Ddd9908B04f952b9cB2A6F8E4D451725ceDC',
value: utils.parseEther('0.1'),
},
});
const {data, sendTransaction} = useSendTransaction(config);
// Wait for the transaction using the hook
const {
data: txReceipt,
error: txError,
isLoading: txLoading,
} = useWaitForTransaction({ confirmations: 1, hash: data?.hash });
console.log('result of wait function', txReceipt, txError, txLoading);
// Wait for the transaction using the wait function
useEffect(() => {
if (data?.wait) {
data
.wait(1)
.then((receipt) => {
console.log('The transaction was successful', receipt);
})
.catch((err) => {
console.log('The transaction failed:', err);
});
}
}, [data]);
return (
<button disabled={!sendTransaction} onClick={() => sendTransaction?.()}>
Send 0.1 ETH
</button>
);
};
Both functions return a promise that when resolved, returns the transaction receipt and when rejected, returns an error.
The wait
function takes in parameter the number of confirmations to wait for, meaning the number of blocks that either contain the transaction or are placed after the block that contains the transaction.
In the other hand, the useWaitForTransaction
hook, takes in parameter an object that needs to contain at least a hash
property for you to pass the transaction hash. You can also pass the number of confirmations to wait for using the confirmations
property.
Passing 1 for the number of confirmations is enough to ensure the transaction is completed and it's the default value.
You can also pass other properties to the useWaitForTransaction
hook like cache properties, the timeout and other things. Everything is explained here:
Transaction receipts and errors
Now, here is what a transaction receipt looks like:
{
"to": "0x5F70Ddd9908B04f952b9cB2A6F8E4D451725ceDC",
"from": "0x5b8f1310A956ee1521A7bB56160451C786289aa9",
"contractAddress": null,
"transactionIndex": 39,
"gasUsed": {
"type": "BigNumber",
"hex": "0x5208"
},
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0x8e6d3739ad7294ad0bbfbf9ec6c8c2d684244f91c0e38f7636535f4ed9cce25b",
"transactionHash": "0x2c5908321162fc944978a6a46a62010d9556d94eb946c46ae65c1946563fd7e8",
"logs": [],
"blockNumber": 7851315,
"confirmations": 1,
"cumulativeGasUsed": {
"type": "BigNumber",
"hex": "0x419e90"
},
"effectiveGasPrice": {
"type": "BigNumber",
"hex": "0x02863829e0"
},
"status": 1,
"type": 2,
"byzantium": true
}
As you can see, there is all the information you need about the transaction. If it failed, the status
property in the receipt will be 0
instead of 1
.
If you want to get more information about the transaction receipt object, check out this article where I show how to get the state of a transaction using EthersJS and at the end I detail all the properties of the transaction receipt and what they do:

Or check out the official documentation here.
Unfortunately, if the transaction fails on the blockchain, the error object returned doesn't give you the reason why it failed.
You can extract it from the error message but it's not very clean and you cannot handle specific types of error differently. If you want to learn how to handle errors properly, check out this guide on how to handle errors when transactions fail using EthersJS.
If tou want to use any feature from the Ethers JS library, you can get an Ethers JS provider by using the useProvider
hook.
And that's it 🎉
Thank you for reading this article