Read and display contract events
This recipe shows how to fetch and display events emitted by your smart contract using the useScaffoldEventHistory hook. You'll learn how to efficiently query, listen, parse, and render contract events in your UI, and see how to extend your project with production-grade event indexing using Subgraph or Ponder.
The useScaffoldEventHistory hook is primarily designed for local development (hardhat/anvil chains). Using it in production environments(mainnet or L2 chains), can cause performance issues and excessive RPC usage. For production applications, consider using specialized indexing solutions like Subgraph or Ponder instead.
Here is the full code, which we will be implementing in the guide below:
import * as React from "react";
import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth";
export const ContractEvents = () => {
const {
data: events,
isLoading,
error,
} = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "GreetingChange",
// fromBlock defaults to deployedOnBlock if available (block number of the contract deployment)
watch: true, // Defaults to false. Set to true to listen for new events in real-time
blockData: true,
});
if (isLoading) return <div>Loading events...</div>;
if (error) return <div>Error loading events: {error.message}</div>;
return (
<div>
<h2>GreetingChange Events</h2>
<ul>
{events?.map(event => (
<li key={`${event.transactionHash}-${event.logIndex}`}>
<p>Setter: {event.args?.greetingSetter}</p>
<p>Greeting: {event.args?.newGreeting}</p>
<p>Premium: {event.args?.premium}</p>
<p>Value: {event.args?.value}</p>
<p>Block: {event.block?.number?.toString()}</p>
</li>
))}
</ul>
</div>
);
};
Implementation guideβ
Step 1: Create a new Componentβ
Create a new component in the "components" folder of your application.
import * as React from "react";
export const ContractEvents = () => {
return <div>Contract Events will be displayed here.</div>;
};
Step 2: Initialize the useScaffoldEventHistory hookβ
Import and initialize the useScaffoldEventHistory hook to fetch events. By default, the hook will start fetching from the block the contract was deployed (deployedOnBlock), so you donβt need to specify fromBlock unless you want to override it.
import * as React from "react";
import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth";
export const ContractEvents = () => {
const {
data: events,
isLoading,
error,
} = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "GreetingChange",
watch: true,
blockData: true,
});
return <div>Contract Events will be displayed here.</div>;
};
Step 3: Display the Eventsβ
Render the events in your UI. Adjust the argument names to match your contract's event signature.
import * as React from "react";
import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth";
export const ContractEvents = () => {
const {
data: events,
isLoading,
error,
} = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "GreetingChange",
watch: true,
blockData: true,
});
return (
<div>
<h2>GreetingChange Events</h2>
<ul>
{events?.map(event => (
<li key={`${event.transactionHash}-${event.logIndex}`}>
<p>Setter: {event.args?.greetingSetter}</p>
<p>Greeting: {event.args?.newGreeting}</p>
<p>Premium: {event.args?.premium}</p>
<p>Value: {event.args?.value}</p>
<p>Block: {event.block?.number?.toString()}</p>
</li>
))}
</ul>
</div>
);
};
Step 4: Bonus handle Loading and Error statesβ
Show feedback to the user while events are loading or if an error occurs.
import * as React from "react";
import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth";
export const ContractEvents = () => {
const {
data: events,
isLoading,
error,
} = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "GreetingChange",
watch: true,
blockData: true,
});
if (isLoading) return <div>Loading events...</div>;
if (error) return <div>Error loading events: {error.message}</div>;
return (
<div>
<h2>GreetingChange Events</h2>
<ul>
{events?.map(event => (
<li key={`${event.transactionHash}-${event.logIndex}`}>
<p>Setter: {event.args?.greetingSetter}</p>
<p>Greeting: {event.args?.newGreeting}</p>
<p>Premium: {event.args?.premium}</p>
<p>Value: {event.args?.value}</p>
<p>Block: {event.block?.number?.toString()}</p>
</li>
))}
</ul>
</div>
);
};
Next Stepsβ
Subgraph (The Graph): For advanced, production-grade event indexing and GraphQL querying, use the Subgraph extension. Install with:
npx create-eth@latest -e subgraphSee the extension docs for setup and deployment.
Ponder: For a TypeScript-first, flexible event indexer suitable for both local development and production, use the Ponder extension. Install with:
npx create-eth@latest -e ponderSee the extension docs for configuration and usage.
Both tools let you efficiently index and query contract events at scale. Choose the one that best fits your stack and workflow.