Skip to main content

Write to a Contract with writeContractAsync button

This recipe shows how to implement a button that allows users to interact with a smart contract by executing the writeContractAsync function returned by useScaffoldWriteContract. By following this guide, you can create a user interface for writing data to a contract.

Here is the full code, which we will be implementing in the guide below:
components/Greetings.tsx
import { useState } from "react";
import { parseEther } from "viem";
import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth";

export const Greetings = () => {
const [newGreeting, setNewGreeting] = useState("");

const { writeContractAsync, isPending } = useScaffoldWriteContract("YourContract");

const handleSetGreeting = async () => {
try {
await writeContractAsync(
{
functionName: "setGreeting",
args: [newGreeting],
value: parseEther("0.01"),
},
{
onBlockConfirmation: txnReceipt => {
console.log("๐Ÿ“ฆ Transaction blockHash", txnReceipt.blockHash);
},
},
);
} catch (e) {
console.error("Error setting greeting", e);
}
};

return (
<>
<input
type="text"
placeholder="Write your greeting"
className="input border border-primary"
onChange={e => setNewGreeting(e.target.value)}
/>
<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. This component will enable users to write data to a smart contract.

components/Greetings.tsx
export const Greetings = () => {
return (
<>
<input type="text" placeholder="Write your greeting" className="input border border-primary" />
<button>Send</button>
</>
);
};

Step 2: Initialize useScaffoldWriteContract hookโ€‹

Initialize the useScaffoldWriteContract hook. This hook provides the writeContractAsync function for sending transactions, we'll create handleSetGreeting function in which we'll call and pass parameters to writeContractAsync required to perform contract interaction.

import { useState } from "react";
import { parseEther } from "viem";
import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth";

export const Greetings = () => {
const [newGreeting, setNewGreeting] = useState("");

const { writeContractAsync } = useScaffoldWriteContract("YourContract");

const handleSetGreeting = async () => {
try {
await writeContractAsync(
{
functionName: "setGreeting",
args: [newGreeting],
value: parseEther("0.01"),
},
{
onBlockConfirmation: txnReceipt => {
console.log("๐Ÿ“ฆ Transaction blockHash", txnReceipt.blockHash);
},
},
);
} catch (e) {
console.error("Error setting greeting", e);
}
};

return (
<>
<input type="text" placeholder="Write your greeting" className="input border border-primary" />
<button>Send</button>
</>
);
};

Step 3: Add input change logic and send transaction when users click the buttonโ€‹

Wire up the input field to update the newGreeting state when the user types in a new greeting and call handleSetGreeting function when user click on the button.

import { parseEther } from "viem";
import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth";

export const Greetings = () => {
const [newGreeting, setNewGreeting] = useState("");

const { writeContractAsync } = useScaffoldWriteContract("YourContract");

const handleSetGreeting = async () => {
try {
await writeContractAsync(
{
functionName: "setGreeting",
args: [newGreeting],
value: parseEther("0.01"),
},
{
onBlockConfirmation: txnReceipt => {
console.log("๐Ÿ“ฆ Transaction blockHash", txnReceipt.blockHash);
},
},
);
} catch (e) {
console.error("Error setting greeting", e);
}
};

return (
<>
<input
type="text"
placeholder="Write your greeting"
className="input border border-primary"
onChange={e => setNewGreeting(e.target.value)}
/>
<button
className="btn btn-primary"
onClick={handleSetGreeting}
>
Send
</button>
</>
);
};

Step 4: Bonus adding loading stateโ€‹

We can use isPending returned from useScaffoldWriteContract while the transaction is being mined and also disable the button.

import { useState } from "react";
import { parseEther } from "viem";
import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth";

export const Greetings = () => {
const [newGreeting, setNewGreeting] = useState("");
const { writeContractAsync, isPending } = useScaffoldWriteContract("YourContract");

const handleSetGreeting = async () => {
try {
await writeContractAsync(
{
functionName: "setGreeting",
args: [newGreeting],
value: parseEther("0.01"),
},
{
onBlockConfirmation: txnReceipt => {
console.log("๐Ÿ“ฆ Transaction blockHash", txnReceipt.blockHash);
},
},
);
} catch (e) {
console.error("Error setting greeting", e);
}
};

return (
<>
<input
type="text"
placeholder="Write your greeting"
className="input border border-primary"
onChange={e => setNewGreeting(e.target.value)}
/>

<button
className="btn btn-primary"
onClick={handleSetGreeting}
disabled={isPending}
>
{isPending ? <span className="loading loading-spinner loading-sm"></span> : "Send"}
</button>
</>
);
};