Skip to main content

useScaffoldEventHistory

Use this hook to fetch and parse historical events emitted by your smart contracts. It supports filtering, pagination, and optional continuous watching for new events.

const { data: events, isLoading } = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "Transfer",
fromBlock: 0n,
});

Configurationโ€‹

ParameterTypeDescription
contractNamestringName of the deployed contract to query events from.
eventNamestringName of the event to retrieve. Autocompleted from contract ABI.
fromBlockbigintStarting block number for event retrieval.
filters (optional)objectEvent parameter filters to narrow results.
blockData (optional)booleanInclude block information with each event. Default: false
transactionData (optional)booleanInclude transaction details with each event. Default: false
receiptData (optional)booleanInclude receipt information with each event. Default: false
watch (optional)booleanEnable continuous polling for new events. Default: false
format (optional)booleanParse and format event data. Default: true
enabled (optional)booleanToggle hook activation. Default: true

Return Valuesโ€‹

PropertyTypeDescription
dataEventData[] | undefinedArray of parsed events with type, args, and parsedArgs
isLoadingbooleantrue while fetching events
errorstring | undefinedError message if the query failed

EventData Structureโ€‹

interface EventData {
type: string; // Event name
args: Record<string, unknown>; // Raw event arguments
parsedArgs: Record<string, any>; // Parsed/formatted arguments
blockNumber?: bigint; // Block number (if blockData: true)
transactionHash?: string; // Tx hash (if transactionData: true)
// ... additional fields based on options
}

Usage Examplesโ€‹

Basic Event Queryโ€‹

import { View, Text, FlatList, ActivityIndicator } from "react-native";
import { useScaffoldEventHistory } from "@/hooks/scaffold-stark";

export default function TransferHistory() {
const { data: transfers, isLoading, error } = useScaffoldEventHistory({
contractName: "Token",
eventName: "Transfer",
fromBlock: 0n,
});

if (isLoading) {
return <ActivityIndicator />;
}

if (error) {
return <Text>Error: {error}</Text>;
}

return (
<FlatList
data={transfers}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View style={{ padding: 12, borderBottomWidth: 1 }}>
<Text>From: {item.parsedArgs.from}</Text>
<Text>To: {item.parsedArgs.to}</Text>
<Text>Amount: {item.parsedArgs.value?.toString()}</Text>
</View>
)}
ListEmptyComponent={<Text>No transfers found</Text>}
/>
);
}

Filtered Eventsโ€‹

import { useScaffoldEventHistory } from "@/hooks/scaffold-stark";
import { useAccount } from "@starknet-react/core";

export default function MyTransfers() {
const { address } = useAccount();

const { data: myTransfers, isLoading } = useScaffoldEventHistory({
contractName: "Token",
eventName: "Transfer",
fromBlock: 0n,
filters: {
from: address, // Only transfers FROM the connected account
},
enabled: !!address, // Only run when address is available
});

// ... render transfers
}

With Block and Transaction Dataโ€‹

import { View, Text, FlatList } from "react-native";
import { useScaffoldEventHistory } from "@/hooks/scaffold-stark";

export default function DetailedEventList() {
const { data: events, isLoading } = useScaffoldEventHistory({
contractName: "NFT",
eventName: "Mint",
fromBlock: 0n,
blockData: true,
transactionData: true,
});

return (
<FlatList
data={events}
renderItem={({ item }) => (
<View style={{ padding: 12 }}>
<Text>Token ID: {item.parsedArgs.tokenId?.toString()}</Text>
<Text>Block: {item.blockNumber?.toString()}</Text>
<Text>Tx: {item.transactionHash?.slice(0, 10)}...</Text>
</View>
)}
/>
);
}

Real-time Event Watchingโ€‹

import { useState, useEffect } from "react";
import { View, Text, FlatList } from "react-native";
import { useScaffoldEventHistory } from "@/hooks/scaffold-stark";

export default function LiveOrderBook() {
const { data: orders, isLoading } = useScaffoldEventHistory({
contractName: "Exchange",
eventName: "OrderPlaced",
fromBlock: 0n,
watch: true, // Poll for new events
});

return (
<View>
<Text style={{ fontWeight: "bold" }}>
Live Orders ({orders?.length || 0})
</Text>
<FlatList
data={orders?.slice(0, 10)} // Show latest 10
renderItem={({ item }) => (
<View style={{ padding: 8 }}>
<Text>
{item.parsedArgs.side}: {item.parsedArgs.amount?.toString()} @ {item.parsedArgs.price?.toString()}
</Text>
</View>
)}
/>
</View>
);
}

Pagination Patternโ€‹

import { useState } from "react";
import { View, Text, Button, FlatList } from "react-native";
import { useScaffoldEventHistory } from "@/hooks/scaffold-stark";

const EVENTS_PER_PAGE = 20;

export default function PaginatedEvents() {
const [fromBlock, setFromBlock] = useState(0n);

const { data: events, isLoading } = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "SomeEvent",
fromBlock,
});

const loadMore = () => {
if (events && events.length > 0) {
const lastEvent = events[events.length - 1];
setFromBlock(lastEvent.blockNumber + 1n);
}
};

return (
<View>
<FlatList
data={events}
renderItem={({ item }) => (
<View style={{ padding: 8 }}>
<Text>{JSON.stringify(item.parsedArgs)}</Text>
</View>
)}
ListFooterComponent={
<Button
title={isLoading ? "Loading..." : "Load More"}
onPress={loadMore}
disabled={isLoading}
/>
}
/>
</View>
);
}

Activity Feedโ€‹

import { View, Text, FlatList, Image } from "react-native";
import { useScaffoldEventHistory } from "@/hooks/scaffold-stark";

export default function ActivityFeed() {
const { data: activities, isLoading } = useScaffoldEventHistory({
contractName: "Social",
eventName: "Activity",
fromBlock: 0n,
blockData: true,
watch: true,
});

const renderActivity = ({ item }) => {
const { activityType, user, data } = item.parsedArgs;

return (
<View style={{ flexDirection: "row", padding: 12, alignItems: "center" }}>
<View style={{ flex: 1 }}>
<Text style={{ fontWeight: "bold" }}>
{user.slice(0, 8)}... {activityType}
</Text>
<Text style={{ color: "gray" }}>
Block #{item.blockNumber?.toString()}
</Text>
</View>
</View>
);
};

if (isLoading && !activities?.length) {
return <Text>Loading activity...</Text>;
}

return (
<FlatList
data={activities}
renderItem={renderActivity}
keyExtractor={(_, index) => index.toString()}
ListEmptyComponent={<Text>No activity yet</Text>}
/>
);
}

Event Filteringโ€‹

Filters are applied at the RPC level for efficiency:

// Filter by single value
filters: {
from: "0x123...",
}

// Multiple filters (AND logic)
filters: {
from: "0x123...",
to: "0x456...",
}
note

Not all event parameters can be filtered. Only indexed parameters in the Cairo event definition support filtering.

Performance Considerationsโ€‹

Large Block Rangesโ€‹

Querying from block 0 on mainnet can be slow. Consider:

// Start from a recent block
const recentBlock = currentBlock - 10000n;

const { data } = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "SomeEvent",
fromBlock: recentBlock,
});

Disable When Not Neededโ€‹

const [showHistory, setShowHistory] = useState(false);

const { data } = useScaffoldEventHistory({
// ...config
enabled: showHistory, // Only fetch when user wants to see history
});

Watch Mode Pollingโ€‹

When watch: true, the hook polls for new events at regular intervals. This is useful for real-time UIs but consumes RPC resources.