Skip to main content
In this guide you send a contract transaction from React, wait for it to confirm, show clear errors and link the user to the transaction on BOTScan.
Everything on this page uses testnet (chain 968). Get free test tokens from the faucet.

What you’ll build

A form that signs a guest book contract on testnet. It moves through four states: waiting for the wallet, sent, confirmed or reverted, and failed. The guest book is deployed at 0x7962412A92E5553E66C794c3a352422DEB7BAc27 on testnet. Its sign(string message) function stores your message.

Prerequisites

Steps

1

Write the component

src/SignGuestBook.tsx
2

Understand the flow

  • write.mutate(...) asks the wallet to sign and send. While the popup is open, write.isPending is true.
  • When the wallet sends it, write.data is the transaction hash. That’s the moment to show the BOTScan link.
  • useWaitForTransactionReceipt polls the RPC until the transaction is in a block. Blocks are fast, so this usually takes a few seconds.
  • A receipt with status: "reverted" means the transaction was mined but failed. The user still paid gas.
  • Passing chainId makes wagmi refuse to send if the wallet is on another network, instead of sending to the wrong chain.
3

Render it

src/App.tsx

Verify it worked

  1. Click Sign and approve in the wallet.
  2. You see Sent: view on BOTScan, then Confirmed in block followed by a number.
  3. Open the BOTScan link. The transaction shows Success and the sign method.

Handle errors

The most common errors, and what errorMessage shows: shortMessage is a one-line summary that is safe to show users. Log the full error to the console for debugging.

Troubleshooting

BOT Chain needs a gas price of at least 20 gwei. Most wallets read it from the RPC, but if yours set a lower price by hand, the transaction won’t be picked up. Send it again with the default gas settings.
The public RPC sometimes drops requests. wagmi retries, but if it gives up, open the BOTScan link to check the status, and call receipt.refetch() to try again.
To catch reverts before the wallet opens, call useSimulateContract with the same arguments and pass simulation.data.request to write.mutate. The button stays disabled until the simulation succeeds.

Next steps

Work without eth_getLogs

Show activity without event queries.

Gasless transactions

Let users act without holding BOT.
Last modified on October 3, 2026