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's null.
  • isLoading: will be true after you call sendTransaction while waiting for the user to confirm the transaction on their wallet. Otherwise it's false.
  • isError: a boolean indicating if trying to send the transaction resulted in an error or not. It's true when error is not null and false otherwise.
  • isSuccess: a boolean indicating if the transaction was successfully sent or not. Before calling sendTransaction, it's also false.
  • 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 simplest request object you can pass is like the one in the example above, just the to property containing the address that receives the ether and a value property that contains the amount to send in wei, that's why I use the parseEther function from Ethers. I use it to change the unit of the amount to send and convert if from ether to wei.
  • 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 the data of the transaction (the hash property and the wait 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 after onSuccess and takes in parameter the data and the eventual error.

If you want to see all the options you can pass, check out the documentation here:

usePrepareSendTransaction – wagmi
Hook for preparing a transaction to be sent.

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:

  1. Use the wait function contained in the data property returned by useSendTransaction.
  2. 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:

useWaitForTransaction – wagmi
React Hook for declaratively waiting until transaction is processed. Pairs well with useContractWrite and useSendTransaction.

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:

How to get the state of a transaction using Ethers JS and JavaScript
In this tutorial, we are going to learn how to get the state of a transaction using Ethers JS and JavaScript.

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