Wagmi useWriteContract
with transaction status
This recipe demonstrates how to create a button for contract interaction using the "useTransactor" and "useWriteContract" hooks from the "wagmi" library. The interaction includes the capability to provide feedback on the transaction status when using wagmi useWriteContract
.
Here is the full code, which we will be implementing in the guide below:
import * as React from "react";
import { parseEther } from "viem";
import { useWriteContract } from "wagmi";
import DeployedContracts from "~~/contracts/deployedContracts";
import { useTransactor } from "~~/hooks/scaffold-eth";
export const ContractInteraction = () => {
const { writeContractAsync, isPending } = useWriteContract();
const writeContractAsyncWithParams = () =>
writeContractAsync({
address: DeployedContracts[31337].YourContract.address,
abi: DeployedContracts[31337].YourContract.abi,
functionName: "setGreeting",
value: parseEther("0.01"),
args: ["Hello world!"],
});
const writeTx = useTransactor();
const handleSetGreeting = async () => {
try {
await writeTx(writeContractAsyncWithParams, { blockConfirmations: 1 });
} catch (e) {
console.log("Unexpected error in writeTx", e);
}
};
return (
<button className="btn btn-primary" onClick={handleSetGreeting} disabled={isPending}>
{isPending ? <span className="loading loading-spinner loading-sm"></span> : "Send"}
</button>
);
};
Implementationโ
Step 1: Set Up Your Componentโ
Create a new component in the "components" folder. The component will show a button that will allow users to interact with your smart contract.
import * as React from "react";
export const ContractInteraction = () => {
return <button>Send</button>;
};
Step 2: Configure wagmi's useWriteContract
hookโ
Add wagmi's useWriteContract
hook and configure writeContractAsync
with the parameters: abi
, address
, functionName
, value
and args
. Get the ABI and address of your smart contract from the DeployedContracts or you can grab it from ExternalContracts object, those will be used to set up the contract interaction.
import * as React from "react";
import { parseEther } from "viem";
import { useWriteContract } from "wagmi";
import DeployedContracts from "~~/contracts/deployedContracts";
export const ContractInteraction = () => {
const { writeContractAsync } = useWriteContract();
const writeContractAsyncWithParams = () =>
writeContractAsync({
address: DeployedContracts[31337].YourContract.address,
abi: DeployedContracts[31337].YourContract.abi,
functionName: "setGreeting",
value: parseEther("0.01"),
args: ["Hello world!"],
});
return <button>Send</button>;
};
Step 3: Initialize useTransactor
hook and send transactionโ
Initialize the useTransactor
hook, and use it to wrap writeContractAsyncWithParams
function which we got from useWriteContract
to show feedback transaction status to user.
import * as React from "react";
import { parseEther } from "viem";
import { useWriteContract } from "wagmi";
import DeployedContracts from "~~/contracts/deployedContracts";
import { useTransactor } from "~~/hooks/scaffold-eth";
export const ContractInteraction = () => {
const { writeContractAsync } = useWriteContract();
const writeContractAsyncWithParams = () =>
writeContractAsync({
address: DeployedContracts[31337].YourContract.address,
abi: DeployedContracts[31337].YourContract.abi,
functionName: "setGreeting",
value: parseEther("0.01"),
args: ["Hello world!"],
});
const writeTx = useTransactor();
return <button onClick={() => writeTx(writeContractAsyncWithParams, { blockConfirmations: 1 })}>Send</button>;
};
Step 4: Wrap useTransactor
in a handler async functionโ
Wrap the writeTx
function in a handler function to start the transaction when the user clicks the button.
import * as React from "react";
import { parseEther } from "viem";
import { useWriteContract } from "wagmi";
import DeployedContracts from "~~/contracts/deployedContracts";
import { useTransactor } from "~~/hooks/scaffold-eth";
export const ContractInteraction = () => {
const { writeContractAsync, isPending } = useWriteContract();
const writeContractAsyncWithParams = () =>
writeContractAsync({
address: DeployedContracts[31337].YourContract.address,
abi: DeployedContracts[31337].YourContract.abi,
functionName: "setGreeting",
value: parseEther("0.01"),
args: ["Hello world!"],
});
const writeTx = useTransactor();
const handleSetGreeting = async () => {
try {
await writeTx(writeContractAsyncWithParams, { blockConfirmations: 1 });
} catch (e) {
console.log("Unexpected error in writeTx", e);
}
};
return (
<button className="btn btn-primary" onClick={handleSetGreeting}>
Send
</button>
);
Step 5: Bonus adding loading stateโ
We can use isPending
returned from useWriteContract
while the transaction is being mined and also disable
the button.
import * as React from "react";
import { parseEther } from "viem";
import { useWriteContract } from "wagmi";
import DeployedContracts from "~~/contracts/deployedContracts";
import { useTransactor } from "~~/hooks/scaffold-eth";
export const ContractInteraction = () => {
const { writeContractAsync, isPending } = useWriteContract();
const writeContractAsyncWithParams = () =>
writeContractAsync({
address: DeployedContracts[31337].YourContract.address,
abi: DeployedContracts[31337].YourContract.abi,
functionName: "setGreeting",
value: parseEther("0.01"),
args: ["Hello world!"],
});
const writeTx = useTransactor();
const handleSetGreeting = async () => {
try {
await writeTx(writeContractAsyncWithParams, { blockConfirmations: 1 });
} catch (e) {
console.log("Unexpected error in writeTx", e);
}
};
return (
<button className="btn btn-primary" onClick={handleSetGreeting} disabled={isPending}>
{isPending ? <span className="loading loading-spinner loading-sm"></span> : "Send"}
</button>
);
};